Implement 3: Complete the native-process CLI, JSON request handling, status vocabulary and exit codes #5

Open
opened 2026-11-02 22:44:50 +00:00 by ai-team-lead · 1 comment
Member

Workflow

  • Repository: projects/product-54354138-1
  • Repository intent: existing_repository
  • Base branch: master
  • Target branch: task/1-task
  • Facade: .agent/project.yaml (initialized)
  • CI: created
  • Created repository: false
  • Created branch: true
  • Facade template: script_toolkit_python
  • Facade action: initialize
  • Project shape: project_kind=script_toolkit, languages=['python'], runtimes=['command_line'], interfaces=['cli'], delivery_kind=native_process
  • Project shape requirement refs: project_kind=['REQ-001', 'REQ-011'], languages=['REQ-001', 'REQ-011'], runtimes=['REQ-001', 'REQ-011'], interfaces=['REQ-001', 'REQ-002', 'REQ-009'], delivery_kind=['REQ-011']
  • Facade placement: kind=repository_root

Team-lead source issue: #2
Parent architecture issue: #1

Developer Task

Complete the native-process CLI, JSON request handling, status vocabulary and exit codes

Scope

Finish tools/example.py as the plain python -m tools.example [REQUEST.json | flags] CLI: parse topic, desired width and height, format (png|ico), source, --count, --download, --output-dir, --resize and --dry-run, or load the same fields from a JSON request document; emit exactly one machine-readable JSON document on stdout containing the used source, the item list and a fixed status vocabulary with matching exit codes (ok=0, dry_run=0, invalid_request=2, no_format=3, no_size=4, access_error=5, partial_download=6). Unsupported formats and an unknown --source produce invalid_request carrying the accepted values and the available source ids. Add tools/envelope.py with the status/exit-code table and response builder, extend tools/errors.py with request errors, keep --help documenting every parameter, and rewrite examples/input.json as the canonical dry_run request example so the facade smoke command stays green and offline.

Acceptance Criteria

  • Affected file tools/envelope.py is valid.
  • Test artifact tests/test_cli.py passes through the standard test entrypoint.
  • Facade command tools.validate succeeds.
  • Facade command tools.test succeeds.
  • Facade command tools.smoke succeeds.
  • Facade acceptance check help-command passes.
  • Capability public_cli is provided by evidence cli-contract-tested, facade-validate-succeeds, facade-test-succeeds, facade-smoke-succeeds, facade-help-command-passes.

Test Hints

  • pytest tests/test_cli.py through the tools.test entrypoint; assert one JSON document on stdout, the status/exit-code table for every branch reachable without network, unknown source listing available ids, unsupported format rejection and --help output.
  • python -m tools.example --help
  • python -m tools.example examples/input.json
  • python -m compileall tools tests
  • tests/test_cli.py
  • tools/envelope.py
  • Add or update focused tests for the changed behavior.
  • Ensure those tests run through the repository's standard CI test entrypoint; a local-only test run is not sufficient.
  • Verification mechanisms declare their executor, phase, prerequisites and evidence format in verification_execution. Task acceptance and final product acceptance are separate phases; service code does not imply an additional artifact publication stage.

Requirement References

  • R1: REQ-001 REQ-001 Утилита является консольным приложением, запускаемым как обычный исполняемый процесс; параметры запуска задают тему поиска, желаемый размер, формат, источник, флаг скачивания и флаг масштабирования.
  • R2: REQ-002 REQ-002 Результат работы выводится в машиночитаемом структурированном виде, пригодном для tool calling ИИ-агентом: перечень найденных изображений с источником, URL, форматом и фактическими размерами, а также однозначное различие между успехом, отсутствием подходящих изображений и ошибкой.
  • R4: REQ-004 REQ-004 Источник изображений выбирается вызывающей стороной через параметр; схема допускает подключение нескольких источников, и в поставку входит как минимум один рабочий бесплатный источник; неизвестный источник даёт явную ошибку с перечнем доступных источников.

Affected Repos / Files

  • tools/example.py
  • tools/envelope.py
  • tools/errors.py
  • examples/input.json
  • tests/test_cli.py

Required Outputs

These outputs are absent facade prerequisites assigned to this task by affected_files; their intents are declarations from the accepted plan.

  • tools/example.py: state=absent_at_planning, intent=modify_final, satisfies=tools, tools/example.py, required_by=tools.smoke, tools.validate
  • tools/envelope.py: state=absent_at_planning, intent=modify_final, satisfies=tools, required_by=tools.validate
  • tools/errors.py: state=absent_at_planning, intent=modify_final, satisfies=tools, required_by=tools.validate
  • examples/input.json: state=absent_at_planning, intent=modify_final, satisfies=examples/input.json, required_by=tools.smoke
  • tests/test_cli.py: state=absent_at_planning, intent=modify_final, satisfies=tests, required_by=tools.validate

Facade Slice Contract

The facade is the global CI contract for the whole task branch. This task may implement only a slice, but it must not contradict the facade layout or modify protected facade/control paths.

  • Task kind: public_interface
  • Facade path: .agent/project.yaml (initialized)
  • Required facade paths: examples/input.json, tests, tests/test_example.py, tools, tools/example.py
  • Support facade paths: .env.example, pyproject.toml, uv.lock
  • Facade commands: tools.dependencies.restore: /opt/agent-environment/bin/python -I -m agent_environment_executor.cli --workspace "$PWD" --component 'tools' --mode restore, tools.validate: python -m compileall tools tests, tools.test: pytest, tools.smoke: python -m tools.example examples/input.json
  • Facade acceptance: import-package (package_import), help-command (cli_command)
  • Protected paths: .agent/acceptance.yaml, .agent/project.yaml, .gitea/workflows/

File Intents

  • tools/example.py: modify_final, ownership_scope=exact_path
  • tools/envelope.py: modify_final, ownership_scope=exact_path
  • tools/errors.py: modify_final, ownership_scope=exact_path
  • examples/input.json: modify_final, ownership_scope=exact_path
  • tests/test_cli.py: modify_final, ownership_scope=exact_path

Acceptance Checks

  • cli-envelope-module-valid artifact_state affected_file:tools/envelope.py expected=valid
  • cli-contract-tested test_result affected_file:tests/test_cli.py expected=passes
  • facade-validate-succeeds facade_command_result facade_command:tools.validate expected=succeeds
  • facade-test-succeeds facade_command_result facade_command:tools.test expected=succeeds
  • facade-smoke-succeeds facade_command_result facade_command:tools.smoke expected=succeeds
  • facade-help-command-passes facade_acceptance_result facade_acceptance:help-command expected=passes
  • public-cli-provided capability_result capability:public_cli expected=provided evidence=cli-contract-tested,facade-validate-succeeds,facade-test-succeeds,facade-smoke-succeeds,facade-help-command-passes

Facade Refs

  • Commands: tools.validate, tools.test, tools.smoke

  • Paths: none

  • Acceptance: help-command

Capability Contract

  • Provides: public_cli (public_interface)
  • Requires: source_registry (external_integration), toolkit_layout (structure)

Integration Contract

  • Functional dependencies: [2]
  • Execution predecessors: [1, 2]
  • Integrate the current target before checks; preserve active product obligations from accepted tasks.
  • Task-local criteria are not inherited. Product changes require explicit add/revise/retire declarations; revisions and retirements require approved authority.
  • Requirement changes: []

Dependencies

Risk Notes

  • Preserve existing public behavior unless explicitly requested.
  • UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes.
  • UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed.
  • UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior.
  • UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized.
  • UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics.
  • Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback.
  • Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results.
  • Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades.

Parent Links

Architecture / Lead Context

The context below describes the whole product. Scope and Acceptance Criteria define local completion; the Integration Contract additionally requires preservation of active product obligations.

Team lead handoff

Parent architecture issue: #1

Source title: Консольная утилита поиска и скачивания изображений для вызова ИИ-агентом

Contract asset: agent-architecture-handoff.v1.json

Contract SHA-256: 2556d39044bc87f828704b28f39f1b136761f18330c69c087a387f1ae69fa2bf

Workflow

  • Repository: projects/product-54354138-1
  • Repository intent: existing_repository
  • Base branch: master
  • Target branch: task/1-task
  • Facade: .agent/project.yaml (initialized)
  • CI: created
  • Created repository: false
  • Created branch: true
  • Facade template: script_toolkit_python
  • Facade action: initialize
  • Project shape: project_kind=script_toolkit, languages=['python'], runtimes=['command_line'], interfaces=['cli'], delivery_kind=native_process
  • Project shape requirement refs: project_kind=['REQ-001', 'REQ-011'], languages=['REQ-001', 'REQ-011'], runtimes=['REQ-001', 'REQ-011'], interfaces=['REQ-001', 'REQ-002', 'REQ-009'], delivery_kind=['REQ-011']
  • Facade placement: kind=repository_root

Architecture Plan

Context

Product request issue #1: a console (CLI) image search/download utility invoked by an AI agent via tool calling. Contract requirements REQ-001..REQ-011: parameters for topic, desired size, format (initial set png/ico), source, download flag and resize flag; machine-readable structured output distinguishing success / no-images-of-format / no-images-of-size / source-access error (AC-001, AC-011); free access without API keys or secrets (REQ-003, AC-002); pluggable source selection with explicit unknown-source error listing available sources (REQ-004, AC-003); only requested format returned and explicit "no images of this format" message distinct from access errors (REQ-007, AC-004); only images not smaller than the desired size in both dimensions, with actual dimensions reported (REQ-006, REQ-008, AC-005, AC-006); download into a caller-specified directory with reported paths (REQ-009, AC-007); downscale-only resizing behind a flag, unchanged dimensions without the flag (REQ-010, AC-008); live-source verification on a known topic (AC-010); delivered and run as a plain executable process with no Docker/containers (REQ-011, AC-009). Approved network access is Wikimedia Commons and Open

Decision

Shape: script_toolkit (Python 3, command_line runtime, cli interface, native_process delivery, repository_root placement). This is the narrowest catalog-template-backed shape that covers every resulting language, runtime, public interface and delivery form: the deliverable is one command-line program that speaks over argv/stdout, there is no HTTP server and no second language, and REQ-011/AC-009 forbid container delivery. 'file_io' is intentionally not declared as a separate public interface: writing downloaded files into the caller-specified directory (REQ-009) and reporting the resulting paths (REQ-002) is internal behavior of the CLI invocation, not an independent repository interface, and declaring it would leave the shape without a supported facade template. Facade: initialize (currently missing) at repository_root, since no product artifact fixes a component root. Implementation direction: a single Python CLI entry module parsed with argparse (topic, desired width/height, format png|ico, source, --count limit, --download, --output-dir, --resize), a small source-adapter registry (Wikimedia Commons MediaWiki API first, Openverse as a second adapter behind the same registry) so

Constraints

  • Project shape is limited to script_toolkit/Python/command_line/cli/native_process at repository_root; do not add an HTTP service, a second language or container packaging.
  • Delivery must be a plain executable process (REQ-011, AC-009): no Dockerfile, compose file or container entrypoint.
  • Only free, credential-free sources; no API keys, tokens, registration or secret configuration may be required or read at runtime (REQ-003, OOS-003).
  • Only Wikimedia Commons and Openverse over HTTPS 443 (incl. subdomains) are approved network destinations; no other hosts and no public-download fallbacks.
  • Format support limited to png and ico (REQ-007, OOS-002); no other formats and no editing beyond downscaling (OOS-001).
  • Output must remain a single machine-readable JSON document with distinct status values and matching exit codes for success, no-format, no-size, access error and invalid request (REQ-002, AC-001, AC-011).
  • Filters must be applied on the client side to the actual downloaded/parsed image data, not trusted from source metadata alone, so reported format and dimensions are real.
  • Resizing may only downscale to the desired size and must be off by default (REQ-010, AC-008).

Risks

  • UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes.
  • UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed.
  • UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior.
  • UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized.
  • UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics.
  • Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback.
  • Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results.
  • Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades.

Team Lead Handoff

  • First prove the smallest end-to-end public path on the live source: run the CLI for a known topic against Wikimedia Commons requesting png, observe a non-empty JSON list with working URLs and real dimensions (AC-010), then confirm the same run with no API key/credential env vars set (AC-002).
  • Bounded check for UNK-001: issue one documented MediaWiki/Openverse search request and record whether size/mime filtering is available server-side and how many candidates must be fetched to satisfy the >= size rule; the decision between server-side parameters and client-side-only filtering (and any candidate cap) depends on that observation.
  • Bounded check for UNK-003: run a handful of sequential requests and record response codes, any 429 behaviour and whether a custom User-Agent is required; the retry/backoff design and whether a --count cap is enforced client-side depend on the result.
  • Bounded check for UNK-002: query an ico request against the chosen source and record whether the no-format status is produced while the source is reachable; this decides how the no-format message is worded and which exit code is paired with it.
  • Bounded check for Pillow availability: attempt prepare_environment with the declared manifest and record whether Pillow resolves from the internal catalog; the choice between Pillow-based ICO decode/resize and a reduced, explicitly recorded capability depends on that result. If it is missing, request operator publication; do not add public index fallbacks or credential changes.
  • Decide and document UNK-004 and UNK-005 with the product owner before finalizing REQ-009 output: default download directory behaviour and the status/exit code for partial download success.
  • All dependency changes must go through the manifests and lock files declared by the generated facade and Tool Backend prepare_environment; agents must not change package sources, credentials, network access or admission policy, and any policy exception requires human approval.
  • Preserve required coverage: every status branch (success, no-format, no-size, access error, invalid/unknown source) needs its own executed check and matching exit code, and aggregate exit 0 must not be treated as proof that the no-format and no-size outcomes work.

Parent architecture issue

Summary

Нужно консольное приложение (CLI), запускаемое как обычный исполняемый процесс, которое по заданной теме находит изображения в бесплатных источниках и по флагу скачивает их. Инструмент предназначен для вызова ИИ-агентом через tool calling, поэтому результат должен быть машиночитаемым и однозначно различать успех, отсутствие подходящих изображений и ошибку. Доступ бесплатный, без API-ключей и регистрации. Источник не принципиален, но выбирается вызывающей стороной, схема допускает несколько подключаемых источников, и в поставку входит как минимум один рабочий бесплатный источник. Задаются тема, желаемый размер и формат из начального набора png/ico. Возвращаются только изображения запрошенного формата, не меньшие желаемого размера; если таких форматов нет — явное сообщение, что изображений такого формата нет; если подходящих по размеру нет — явное сообщение, что подходящих по размеру нет. При наличии флага масштабирования изображения больше желаемого размера уменьшаются до желаемого. Запуск — как обычный процесс, без Docker. Сетевой доступ к бесплатным источникам согласован пользователем вне этого обсуждения (Wikimedia Commons и Openverse, HTTPS 443, включая поддомены).

Requirements

  • REQ-001 REQ-001 Утилита является консольным приложением, запускаемым как обычный исполняемый процесс; параметры запуска задают тему поиска, желаемый размер, формат, источник, флаг скачивания и флаг масштабирования.
  • REQ-002 REQ-002 Результат работы выводится в машиночитаемом структурированном виде, пригодном для tool calling ИИ-агентом: перечень найденных изображений с источником, URL, форматом и фактическими размерами, а также однозначное различие между успехом, отсутствием подходящих изображений и ошибкой.
  • REQ-003 REQ-003 Доступ к источникам бесплатный, без API-ключей, регистрации и иных учётных данных; поиск выполняется без настройки секретов.
  • REQ-004 REQ-004 Источник изображений выбирается вызывающей стороной через параметр; схема допускает подключение нескольких источников, и в поставку входит как минимум один рабочий бесплатный источник; неизвестный источник даёт явную ошибку с перечнем доступных источников.
  • REQ-005 REQ-005 Поиск выполняется по теме (текстовому запросу), задаваемой вызывающей стороной; количество возвращаемых результатов может быть ограничено вызывающей стороной.
  • REQ-006 REQ-006 Вызывающая сторона задаёт желаемый размер изображения (ширина/высота); в результатах по каждому изображению указываются его фактические размеры.
  • REQ-007 REQ-007 Формат изображения выбирается из начального набора png и ico; возвращаются только файлы запрошенного формата, а при отсутствии таких изображений у источника выдаётся явное сообщение, что изображений такого формата нет, отличимое от ошибки доступа к источнику.
  • REQ-008 REQ-008 Возвращаются только изображения, размер которых не меньше желаемого по обоим измерениям; если у источника по теме нет изображений подходящего размера, выдаётся явное сообщение, что подходящих по размеру нет, отличимое от сообщения об отсутствии формата и от ошибки доступа.
  • REQ-009 REQ-009 По флагу скачивания найденные изображения сохраняются в каталог, указанный вызывающей стороной, а в результате сообщаются пути сохранённых файлов.
  • REQ-010 REQ-010 При наличии флага масштабирования изображения, доступные только в размере больше желаемого, уменьшаются до желаемого размера; без этого флага изображения сохраняются без изменения размеров.
  • REQ-011 REQ-011 Утилита поставляется и запускается как обычный исполняемый процесс, без Docker и контейнеров.

Artifacts

None recorded.

Delivery Requirements

  • native_process (requirements=['REQ-011'])

External Inputs

None recorded.

Acceptance Criteria

  • AC-001 AC-001 Для заданной темы утилита возвращает машиночитаемый список результатов, в каждом элементе есть URL, формат и фактические размеры; успешный поиск, отсутствие подходящих изображений и сбой различимы по коду завершения и структуре вывода.
  • AC-002 AC-002 Поиск успешно выполняется в окружении, где не задано ни одного API-ключа или учётных данных.
  • AC-003 AC-003 Указание источника в параметрах приводит к использованию соответствующего источника, и использованный источник явно отражён в выводе; неизвестный источник даёт явную ошибку с перечнем доступных источников.
  • AC-004 AC-004 Запрос формата png возвращает только реальные png-файлы; запрос ico при отсутствии ico у источника даёт явное сообщение о том, что изображений такого формата нет, и это сообщение отличимо от сообщения об ошибке доступа к источнику.
  • AC-005 AC-005 При запросе желаемого размера в выдаче присутствуют только изображения, размер которых не меньше желаемого по обоим измерениям, и для каждого указаны фактические размеры.
  • AC-006 AC-006 Если по теме у источника есть только изображения меньше желаемого размера, вывод содержит явное сообщение, что подходящих по размеру нет, и это сообщение отличимо от сообщения об отсутствии формата и от ошибки доступа.
  • AC-007 AC-007 При указании флага скачивания файлы физически сохранены в заданном каталоге, пути в выводе соответствуют существующим файлам, и файлы открываются как изображения заявленного формата.
  • AC-008 AC-008 При наличии флага масштабирования изображение, найденное в размере больше желаемого, сохраняется с размерами, равными желаемым; без этого флага фактические размеры сохранённого файла совпадают с исходными.
  • AC-009 AC-009 Утилита запускается как обычный исполняемый процесс без Docker и без контейнерной обвязки.
  • AC-010 AC-010 Реальная проверка на известном результате: запрос по теме, для которой у выбранного источника заведомо есть изображения, возвращает непустой список с рабочими ссылками на файлы (проверка на живом источнике, а не только на синтетических данных).
  • AC-011 AC-011 При запрещённом сетевом доступе к источнику утилита завершается явной ошибкой доступа и не выдаёт результат, выглядящий как успешный поиск.

Out of Scope

  • OOS-001 Генерация изображений и любые операции редактирования, кроме уменьшения до желаемого размера
  • OOS-002 Форматы изображений вне начального набора png/ico
  • OOS-003 Платные и требующие API-ключей источники изображений
  • OOS-004 Запуск в Docker/контейнерах
  • OOS-005 Графический интерфейс пользователя

Unknowns / Risks

  • UNK-001 Какой именно бесплатный источник реализуется первым и покрывает ли его API фильтрацию по размеру/формату или фильтрация выполняется на стороне клиента (влияет на объём загружаемых данных)
  • UNK-002 Практическая доступность файлов формата ico у бесплатных источников: ожидаемо такие запросы будут часто возвращать сообщение об отсутствии формата
  • UNK-003 Ограничения частоты запросов и требования к идентификации клиента (user agent) у выбранного бесплатного источника
  • UNK-004 Каталог сохранения по умолчанию, если вызывающая сторона не задала его явно
  • UNK-005 Как сообщать частичный успех скачивания, когда часть файлов сохранилась, а часть нет

Workflow

  • Readiness: ready_for_architecture
  • Contract asset: agent-product-contract.v1.json
  • Contract SHA-256: b7622222e96d133d4c82b5d716cb2963e8b786272d2735fe9033295141b75ba6
  • Transcript: https://git.p2prod.ru/platform/product-requests/issues/1
  • Generated by: product-manager-agent

Architect plan comments

Architecture Plan

Context

Product request issue #1: a console (CLI) image search/download utility invoked by an AI agent via tool calling. Contract requirements REQ-001..REQ-011: parameters for topic, desired size, format (initial set png/ico), source, download flag and resize flag; machine-readable structured output distinguishing success / no-images-of-format / no-images-of-size / source-access error (AC-001, AC-011); free access without API keys or secrets (REQ-003, AC-002); pluggable source selection with explicit unknown-source error listing available sources (REQ-004, AC-003); only requested format returned and explicit "no images of this format" message distinct from access errors (REQ-007, AC-004); only images not smaller than the desired size in both dimensions, with actual dimensions reported (REQ-006, REQ-008, AC-005, AC-006); download into a caller-specified directory with reported paths (REQ-009, AC-007); downscale-only resizing behind a flag, unchanged dimensions without the flag (REQ-010, AC-008); live-source verification on a known topic (AC-010); delivered and run as a plain executable process with no Docker/containers (REQ-011, AC-009). Approved network access is Wikimedia Commons and Open

Decision

Shape: script_toolkit (Python 3, command_line runtime, cli interface, native_process delivery, repository_root placement). This is the narrowest catalog-template-backed shape that covers every resulting language, runtime, public interface and delivery form: the deliverable is one command-line program that speaks over argv/stdout, there is no HTTP server and no second language, and REQ-011/AC-009 forbid container delivery. 'file_io' is intentionally not declared as a separate public interface: writing downloaded files into the caller-specified directory (REQ-009) and reporting the resulting paths (REQ-002) is internal behavior of the CLI invocation, not an independent repository interface, and declaring it would leave the shape without a supported facade template. Facade: initialize (currently missing) at repository_root, since no product artifact fixes a component root. Implementation direction: a single Python CLI entry module parsed with argparse (topic, desired width/height, format png|ico, source, --count limit, --download, --output-dir, --resize), a small source-adapter registry (Wikimedia Commons MediaWiki API first, Openverse as a second adapter behind the same registry) so

Constraints

  • Project shape is limited to script_toolkit/Python/command_line/cli/native_process at repository_root; do not add an HTTP service, a second language or container packaging.
  • Delivery must be a plain executable process (REQ-011, AC-009): no Dockerfile, compose file or container entrypoint.
  • Only free, credential-free sources; no API keys, tokens, registration or secret configuration may be required or read at runtime (REQ-003, OOS-003).
  • Only Wikimedia Commons and Openverse over HTTPS 443 (incl. subdomains) are approved network destinations; no other hosts and no public-download fallbacks.
  • Format support limited to png and ico (REQ-007, OOS-002); no other formats and no editing beyond downscaling (OOS-001).
  • Output must remain a single machine-readable JSON document with distinct status values and matching exit codes for success, no-format, no-size, access error and invalid request (REQ-002, AC-001, AC-011).
  • Filters must be applied on the client side to the actual downloaded/parsed image data, not trusted from source metadata alone, so reported format and dimensions are real.
  • Resizing may only downscale to the desired size and must be off by default (REQ-010, AC-008).

Risks

  • UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes.
  • UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed.
  • UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior.
  • UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized.
  • UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics.
  • Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback.
  • Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results.
  • Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades.

Team Lead Handoff

  • First prove the smallest end-to-end public path on the live source: run the CLI for a known topic against Wikimedia Commons requesting png, observe a non-empty JSON list with working URLs and real dimensions (AC-010), then confirm the same run with no API key/credential env vars set (AC-002).
  • Bounded check for UNK-001: issue one documented MediaWiki/Openverse search request and record whether size/mime filtering is available server-side and how many candidates must be fetched to satisfy the >= size rule; the decision between server-side parameters and client-side-only filtering (and any candidate cap) depends on that observation.
  • Bounded check for UNK-003: run a handful of sequential requests and record response codes, any 429 behaviour and whether a custom User-Agent is required; the retry/backoff design and whether a --count cap is enforced client-side depend on the result.
  • Bounded check for UNK-002: query an ico request against the chosen source and record whether the no-format status is produced while the source is reachable; this decides how the no-format message is worded and which exit code is paired with it.
  • Bounded check for Pillow availability: attempt prepare_environment with the declared manifest and record whether Pillow resolves from the internal catalog; the choice between Pillow-based ICO decode/resize and a reduced, explicitly recorded capability depends on that result. If it is missing, request operator publication; do not add public index fallbacks or credential changes.
  • Decide and document UNK-004 and UNK-005 with the product owner before finalizing REQ-009 output: default download directory behaviour and the status/exit code for partial download success.
  • All dependency changes must go through the manifests and lock files declared by the generated facade and Tool Backend prepare_environment; agents must not change package sources, credentials, network access or admission policy, and any policy exception requires human approval.
  • Preserve required coverage: every status branch (success, no-format, no-size, access error, invalid/unknown source) needs its own executed check and matching exit code, and aggregate exit 0 must not be treated as proof that the no-format and no-size outcomes work.
<!-- agent-developer-task {"asset": "agent-developer-task.v1.json", "renderer": "agent.developer_task_markdown.v1", "schema": "agent.developer_task.v1", "sha256": "1f3f802b4d2859f9807289b41a7c306ab037b4f6c08cafc7ae36c71cddeff14b"} --> ## Workflow - Repository: projects/product-54354138-1 - Repository intent: existing_repository - Base branch: `master` - Target branch: `task/1-task` - Facade: `.agent/project.yaml` (`initialized`) - CI: `created` - Created repository: `false` - Created branch: `true` - Facade template: `script_toolkit_python` - Facade action: `initialize` - Project shape: `project_kind=script_toolkit, languages=['python'], runtimes=['command_line'], interfaces=['cli'], delivery_kind=native_process` - Project shape requirement refs: `project_kind=['REQ-001', 'REQ-011'], languages=['REQ-001', 'REQ-011'], runtimes=['REQ-001', 'REQ-011'], interfaces=['REQ-001', 'REQ-002', 'REQ-009'], delivery_kind=['REQ-011']` - Facade placement: `kind=repository_root` <!-- agent-provisioner:task base_branch=master target_branch=task/1-task --> <!-- teamlead-agent:child source=2 parent=1 index=3 depends_on=1,2 kind=public_interface criteria_scope=facade_slice --> <!-- agent-change-contract {"acceptance_checks": [{"expected": "valid", "id": "cli-envelope-module-valid", "kind": "artifact_state", "supporting_check_ids": [], "target": "tools/envelope.py", "target_type": "affected_file"}, {"expected": "passes", "id": "cli-contract-tested", "kind": "test_result", "supporting_check_ids": [], "target": "tests/test_cli.py", "target_type": "affected_file"}, {"expected": "succeeds", "id": "facade-validate-succeeds", "kind": "facade_command_result", "supporting_check_ids": [], "target": "tools.validate", "target_type": "facade_command"}, {"expected": "succeeds", "id": "facade-test-succeeds", "kind": "facade_command_result", "supporting_check_ids": [], "target": "tools.test", "target_type": "facade_command"}, {"expected": "succeeds", "id": "facade-smoke-succeeds", "kind": "facade_command_result", "supporting_check_ids": [], "target": "tools.smoke", "target_type": "facade_command"}, {"expected": "passes", "id": "facade-help-command-passes", "kind": "facade_acceptance_result", "supporting_check_ids": [], "target": "help-command", "target_type": "facade_acceptance"}, {"expected": "provided", "id": "public-cli-provided", "kind": "capability_result", "supporting_check_ids": ["cli-contract-tested", "facade-validate-succeeds", "facade-test-succeeds", "facade-smoke-succeeds", "facade-help-command-passes"], "target": "public_cli", "target_type": "capability"}], "approved_changes": [], "baseline": [], "execution_after": [1, 2], "functional_dependencies": [2], "integration_policy": "current_target", "obligation_state_transitions": [], "provisioned_control_files": [{"operation": "initialize", "path": ".agent/project.yaml", "sha256": "02a8118add68955267bd8fbb329289e2fe0525c554a38467a9d31bb71dcb3948"}, {"operation": "materialize", "path": ".gitea/workflows/ci.yaml", "sha256": "f8dbd52316fad573eb1a0aa52ceb5df8577c962fa07662670eb6f2bfcdb04c36"}], "required_dependency_updates": [], "schema": "agent.change_contract.v2", "source": 2, "source_requirements": {"R1": "`REQ-001` REQ-001 Утилита является консольным приложением, запускаемым как обычный исполняемый процесс; параметры запуска задают тему поиска, желаемый размер, формат, источник, флаг скачивания и флаг масштабирования.", "R10": "`REQ-010` REQ-010 При наличии флага масштабирования изображения, доступные только в размере больше желаемого, уменьшаются до желаемого размера; без этого флага изображения сохраняются без изменения размеров.", "R11": "`REQ-011` REQ-011 Утилита поставляется и запускается как обычный исполняемый процесс, без Docker и контейнеров.", "R2": "`REQ-002` REQ-002 Результат работы выводится в машиночитаемом структурированном виде, пригодном для tool calling ИИ-агентом: перечень найденных изображений с источником, URL, форматом и фактическими размерами, а также однозначное различие между успехом, отсутствием подходящих изображений и ошибкой.", "R3": "`REQ-003` REQ-003 Доступ к источникам бесплатный, без API-ключей, регистрации и иных учётных данных; поиск выполняется без настройки секретов.", "R4": "`REQ-004` REQ-004 Источник изображений выбирается вызывающей стороной через параметр; схема допускает подключение нескольких источников, и в поставку входит как минимум один рабочий бесплатный источник; неизвестный источник даёт явную ошибку с перечнем доступных источников.", "R5": "`REQ-005` REQ-005 Поиск выполняется по теме (текстовому запросу), задаваемой вызывающей стороной; количество возвращаемых результатов может быть ограничено вызывающей стороной.", "R6": "`REQ-006` REQ-006 Вызывающая сторона задаёт желаемый размер изображения (ширина/высота); в результатах по каждому изображению указываются его фактические размеры.", "R7": "`REQ-007` REQ-007 Формат изображения выбирается из начального набора png и ico; возвращаются только файлы запрошенного формата, а при отсутствии таких изображений у источника выдаётся явное сообщение, что изображений такого формата нет, отличимое от ошибки доступа к источнику.", "R8": "`REQ-008` REQ-008 Возвращаются только изображения, размер которых не меньше желаемого по обоим измерениям; если у источника по теме нет изображений подходящего размера, выдаётся явное сообщение, что подходящих по размеру нет, отличимое от сообщения об отсутствии формата и от ошибки доступа.", "R9": "`REQ-009` REQ-009 По флагу скачивания найденные изображения сохраняются в каталог, указанный вызывающей стороной, а в результате сообщаются пути сохранённых файлов."}, "task_index": 3, "verification_execution": [{"evidence_kind": "facade_acceptance_result", "evidence_schema": "agent.ci_result.v1", "executor": "ci", "mechanism_id": "help-command", "mechanism_kind": "facade_acceptance", "phase": "task_acceptance", "required_paths": ["examples/input.json", "tools/example.py"], "revision_binding": "exact_commit"}, {"evidence_kind": "facade_command_result", "evidence_schema": "agent.ci_result.v1", "executor": "ci", "mechanism_id": "tools.smoke", "mechanism_kind": "facade_command", "phase": "task_acceptance", "required_paths": ["examples/input.json", "pyproject.toml", "tools/example.py"], "revision_binding": "exact_commit"}, {"evidence_kind": "facade_command_result", "evidence_schema": "agent.ci_result.v1", "executor": "ci", "mechanism_id": "tools.test", "mechanism_kind": "facade_command", "phase": "task_acceptance", "required_paths": ["pyproject.toml", "tests/test_example.py"], "revision_binding": "exact_commit"}, {"evidence_kind": "facade_command_result", "evidence_schema": "agent.ci_result.v1", "executor": "ci", "mechanism_id": "tools.validate", "mechanism_kind": "facade_command", "phase": "task_acceptance", "required_paths": ["pyproject.toml", "tests", "tools"], "revision_binding": "exact_commit"}]} --> Team-lead source issue: #2 Parent architecture issue: #1 ## Developer Task Complete the native-process CLI, JSON request handling, status vocabulary and exit codes ## Scope Finish tools/example.py as the plain `python -m tools.example [REQUEST.json | flags]` CLI: parse topic, desired width and height, format (png|ico), source, --count, --download, --output-dir, --resize and --dry-run, or load the same fields from a JSON request document; emit exactly one machine-readable JSON document on stdout containing the used source, the item list and a fixed status vocabulary with matching exit codes (ok=0, dry_run=0, invalid_request=2, no_format=3, no_size=4, access_error=5, partial_download=6). Unsupported formats and an unknown --source produce invalid_request carrying the accepted values and the available source ids. Add tools/envelope.py with the status/exit-code table and response builder, extend tools/errors.py with request errors, keep --help documenting every parameter, and rewrite examples/input.json as the canonical dry_run request example so the facade smoke command stays green and offline. ## Acceptance Criteria - Affected file `tools/envelope.py` is `valid`. - Test artifact `tests/test_cli.py` `passes` through the standard test entrypoint. - Facade command `tools.validate` `succeeds`. - Facade command `tools.test` `succeeds`. - Facade command `tools.smoke` `succeeds`. - Facade acceptance check `help-command` `passes`. - Capability `public_cli` is `provided` by evidence `cli-contract-tested`, `facade-validate-succeeds`, `facade-test-succeeds`, `facade-smoke-succeeds`, `facade-help-command-passes`. ## Test Hints - pytest tests/test_cli.py through the tools.test entrypoint; assert one JSON document on stdout, the status/exit-code table for every branch reachable without network, unknown source listing available ids, unsupported format rejection and --help output. - python -m tools.example --help - python -m tools.example examples/input.json - python -m compileall tools tests - tests/test_cli.py - tools/envelope.py - Add or update focused tests for the changed behavior. - Ensure those tests run through the repository's standard CI test entrypoint; a local-only test run is not sufficient. - Verification mechanisms declare their executor, phase, prerequisites and evidence format in verification_execution. Task acceptance and final product acceptance are separate phases; service code does not imply an additional artifact publication stage. ## Requirement References - R1: `REQ-001` REQ-001 Утилита является консольным приложением, запускаемым как обычный исполняемый процесс; параметры запуска задают тему поиска, желаемый размер, формат, источник, флаг скачивания и флаг масштабирования. - R2: `REQ-002` REQ-002 Результат работы выводится в машиночитаемом структурированном виде, пригодном для tool calling ИИ-агентом: перечень найденных изображений с источником, URL, форматом и фактическими размерами, а также однозначное различие между успехом, отсутствием подходящих изображений и ошибкой. - R4: `REQ-004` REQ-004 Источник изображений выбирается вызывающей стороной через параметр; схема допускает подключение нескольких источников, и в поставку входит как минимум один рабочий бесплатный источник; неизвестный источник даёт явную ошибку с перечнем доступных источников. ## Affected Repos / Files - tools/example.py - tools/envelope.py - tools/errors.py - examples/input.json - tests/test_cli.py ## Required Outputs These outputs are absent facade prerequisites assigned to this task by `affected_files`; their intents are declarations from the accepted plan. - `tools/example.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tools`, `tools/example.py`, required_by=`tools.smoke`, `tools.validate` - `tools/envelope.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tools`, required_by=`tools.validate` - `tools/errors.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tools`, required_by=`tools.validate` - `examples/input.json`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`examples/input.json`, required_by=`tools.smoke` - `tests/test_cli.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tests`, required_by=`tools.validate` ## Facade Slice Contract The facade is the global CI contract for the whole task branch. This task may implement only a slice, but it must not contradict the facade layout or modify protected facade/control paths. - Task kind: `public_interface` - Facade path: `.agent/project.yaml` (`initialized`) - Required facade paths: `examples/input.json`, `tests`, `tests/test_example.py`, `tools`, `tools/example.py` - Support facade paths: `.env.example`, `pyproject.toml`, `uv.lock` - Facade commands: tools.dependencies.restore: `/opt/agent-environment/bin/python -I -m agent_environment_executor.cli --workspace "$PWD" --component 'tools' --mode restore`, tools.validate: `python -m compileall tools tests`, tools.test: `pytest`, tools.smoke: `python -m tools.example examples/input.json` - Facade acceptance: import-package (package_import), help-command (cli_command) - Protected paths: `.agent/acceptance.yaml`, `.agent/project.yaml`, `.gitea/workflows/` ## File Intents - `tools/example.py`: `modify_final`, ownership_scope=`exact_path` - `tools/envelope.py`: `modify_final`, ownership_scope=`exact_path` - `tools/errors.py`: `modify_final`, ownership_scope=`exact_path` - `examples/input.json`: `modify_final`, ownership_scope=`exact_path` - `tests/test_cli.py`: `modify_final`, ownership_scope=`exact_path` ## Acceptance Checks - `cli-envelope-module-valid` `artifact_state` `affected_file:tools/envelope.py` expected=`valid` - `cli-contract-tested` `test_result` `affected_file:tests/test_cli.py` expected=`passes` - `facade-validate-succeeds` `facade_command_result` `facade_command:tools.validate` expected=`succeeds` - `facade-test-succeeds` `facade_command_result` `facade_command:tools.test` expected=`succeeds` - `facade-smoke-succeeds` `facade_command_result` `facade_command:tools.smoke` expected=`succeeds` - `facade-help-command-passes` `facade_acceptance_result` `facade_acceptance:help-command` expected=`passes` - `public-cli-provided` `capability_result` `capability:public_cli` expected=`provided` evidence=cli-contract-tested,facade-validate-succeeds,facade-test-succeeds,facade-smoke-succeeds,facade-help-command-passes ## Facade Refs - Commands: `tools.validate`, `tools.test`, `tools.smoke` - Paths: _none_ - Acceptance: `help-command` ## Capability Contract - Provides: `public_cli` (`public_interface`) - Requires: `source_registry` (`external_integration`), `toolkit_layout` (`structure`) ## Integration Contract - Functional dependencies: [2] - Execution predecessors: [1, 2] - Integrate the current target before checks; preserve active product obligations from accepted tasks. - Task-local criteria are not inherited. Product changes require explicit add/revise/retire declarations; revisions and retirements require approved authority. - Requirement changes: `[]` ## Dependencies - Child task #3 - Child task #4 - Call out any dependency that blocks implementation. ## Risk Notes - Preserve existing public behavior unless explicitly requested. - UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes. - UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed. - UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior. - UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized. - UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics. - Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback. - Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results. - Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades. ## Parent Links - Team-lead issue: #2 - Parent architecture issue: #1 ## Architecture / Lead Context The context below describes the whole product. Scope and Acceptance Criteria define local completion; the Integration Contract additionally requires preservation of active product obligations. # Team lead handoff <!-- agent-architecture-handoff {"asset": "agent-architecture-handoff.v1.json", "renderer": "agent.architecture_handoff_markdown.v1", "schema": "agent.architecture_handoff.v1", "sha256": "2556d39044bc87f828704b28f39f1b136761f18330c69c087a387f1ae69fa2bf"} --> Parent architecture issue: #1 Source title: Консольная утилита поиска и скачивания изображений для вызова ИИ-агентом Contract asset: `agent-architecture-handoff.v1.json` Contract SHA-256: `2556d39044bc87f828704b28f39f1b136761f18330c69c087a387f1ae69fa2bf` ## Workflow - Repository: projects/product-54354138-1 - Repository intent: existing_repository - Base branch: `master` - Target branch: `task/1-task` - Facade: `.agent/project.yaml` (`initialized`) - CI: `created` - Created repository: `false` - Created branch: `true` - Facade template: `script_toolkit_python` - Facade action: `initialize` - Project shape: `project_kind=script_toolkit, languages=['python'], runtimes=['command_line'], interfaces=['cli'], delivery_kind=native_process` - Project shape requirement refs: `project_kind=['REQ-001', 'REQ-011'], languages=['REQ-001', 'REQ-011'], runtimes=['REQ-001', 'REQ-011'], interfaces=['REQ-001', 'REQ-002', 'REQ-009'], delivery_kind=['REQ-011']` - Facade placement: `kind=repository_root` <!-- agent-provisioner:task base_branch=master target_branch=task/1-task --> <!-- architect-agent:plan mode=llm --> ## Architecture Plan ### Context Product request issue #1: a console (CLI) image search/download utility invoked by an AI agent via tool calling. Contract requirements REQ-001..REQ-011: parameters for topic, desired size, format (initial set png/ico), source, download flag and resize flag; machine-readable structured output distinguishing success / no-images-of-format / no-images-of-size / source-access error (AC-001, AC-011); free access without API keys or secrets (REQ-003, AC-002); pluggable source selection with explicit unknown-source error listing available sources (REQ-004, AC-003); only requested format returned and explicit "no images of this format" message distinct from access errors (REQ-007, AC-004); only images not smaller than the desired size in both dimensions, with actual dimensions reported (REQ-006, REQ-008, AC-005, AC-006); download into a caller-specified directory with reported paths (REQ-009, AC-007); downscale-only resizing behind a flag, unchanged dimensions without the flag (REQ-010, AC-008); live-source verification on a known topic (AC-010); delivered and run as a plain executable process with no Docker/containers (REQ-011, AC-009). Approved network access is Wikimedia Commons and Open ### Decision Shape: script_toolkit (Python 3, command_line runtime, cli interface, native_process delivery, repository_root placement). This is the narrowest catalog-template-backed shape that covers every resulting language, runtime, public interface and delivery form: the deliverable is one command-line program that speaks over argv/stdout, there is no HTTP server and no second language, and REQ-011/AC-009 forbid container delivery. 'file_io' is intentionally not declared as a separate public interface: writing downloaded files into the caller-specified directory (REQ-009) and reporting the resulting paths (REQ-002) is internal behavior of the CLI invocation, not an independent repository interface, and declaring it would leave the shape without a supported facade template. Facade: initialize (currently missing) at repository_root, since no product artifact fixes a component root. Implementation direction: a single Python CLI entry module parsed with argparse (topic, desired width/height, format png|ico, source, --count limit, --download, --output-dir, --resize), a small source-adapter registry (Wikimedia Commons MediaWiki API first, Openverse as a second adapter behind the same registry) so ### Constraints - Project shape is limited to script_toolkit/Python/command_line/cli/native_process at repository_root; do not add an HTTP service, a second language or container packaging. - Delivery must be a plain executable process (REQ-011, AC-009): no Dockerfile, compose file or container entrypoint. - Only free, credential-free sources; no API keys, tokens, registration or secret configuration may be required or read at runtime (REQ-003, OOS-003). - Only Wikimedia Commons and Openverse over HTTPS 443 (incl. subdomains) are approved network destinations; no other hosts and no public-download fallbacks. - Format support limited to png and ico (REQ-007, OOS-002); no other formats and no editing beyond downscaling (OOS-001). - Output must remain a single machine-readable JSON document with distinct status values and matching exit codes for success, no-format, no-size, access error and invalid request (REQ-002, AC-001, AC-011). - Filters must be applied on the client side to the actual downloaded/parsed image data, not trusted from source metadata alone, so reported format and dimensions are real. - Resizing may only downscale to the desired size and must be off by default (REQ-010, AC-008). ### Risks - UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes. - UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed. - UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior. - UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized. - UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics. - Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback. - Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results. - Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades. ### Team Lead Handoff - First prove the smallest end-to-end public path on the live source: run the CLI for a known topic against Wikimedia Commons requesting png, observe a non-empty JSON list with working URLs and real dimensions (AC-010), then confirm the same run with no API key/credential env vars set (AC-002). - Bounded check for UNK-001: issue one documented MediaWiki/Openverse search request and record whether size/mime filtering is available server-side and how many candidates must be fetched to satisfy the >= size rule; the decision between server-side parameters and client-side-only filtering (and any candidate cap) depends on that observation. - Bounded check for UNK-003: run a handful of sequential requests and record response codes, any 429 behaviour and whether a custom User-Agent is required; the retry/backoff design and whether a --count cap is enforced client-side depend on the result. - Bounded check for UNK-002: query an ico request against the chosen source and record whether the no-format status is produced while the source is reachable; this decides how the no-format message is worded and which exit code is paired with it. - Bounded check for Pillow availability: attempt prepare_environment with the declared manifest and record whether Pillow resolves from the internal catalog; the choice between Pillow-based ICO decode/resize and a reduced, explicitly recorded capability depends on that result. If it is missing, request operator publication; do not add public index fallbacks or credential changes. - Decide and document UNK-004 and UNK-005 with the product owner before finalizing REQ-009 output: default download directory behaviour and the status/exit code for partial download success. - All dependency changes must go through the manifests and lock files declared by the generated facade and Tool Backend prepare_environment; agents must not change package sources, credentials, network access or admission policy, and any policy exception requires human approval. - Preserve required coverage: every status branch (success, no-format, no-size, access error, invalid/unknown source) needs its own executed check and matching exit code, and aggregate exit 0 must not be treated as proof that the no-format and no-size outcomes work. # Parent architecture issue <!-- agent-contract {"asset": "agent-product-contract.v1.json", "renderer": "agent.product_contract_markdown.v1", "schema": "agent.product_contract.v1", "sha256": "b7622222e96d133d4c82b5d716cb2963e8b786272d2735fe9033295141b75ba6"} --> ## Summary Нужно консольное приложение (CLI), запускаемое как обычный исполняемый процесс, которое по заданной теме находит изображения в бесплатных источниках и по флагу скачивает их. Инструмент предназначен для вызова ИИ-агентом через tool calling, поэтому результат должен быть машиночитаемым и однозначно различать успех, отсутствие подходящих изображений и ошибку. Доступ бесплатный, без API-ключей и регистрации. Источник не принципиален, но выбирается вызывающей стороной, схема допускает несколько подключаемых источников, и в поставку входит как минимум один рабочий бесплатный источник. Задаются тема, желаемый размер и формат из начального набора png/ico. Возвращаются только изображения запрошенного формата, не меньшие желаемого размера; если таких форматов нет — явное сообщение, что изображений такого формата нет; если подходящих по размеру нет — явное сообщение, что подходящих по размеру нет. При наличии флага масштабирования изображения больше желаемого размера уменьшаются до желаемого. Запуск — как обычный процесс, без Docker. Сетевой доступ к бесплатным источникам согласован пользователем вне этого обсуждения (Wikimedia Commons и Openverse, HTTPS 443, включая поддомены). ## Requirements - `REQ-001` REQ-001 Утилита является консольным приложением, запускаемым как обычный исполняемый процесс; параметры запуска задают тему поиска, желаемый размер, формат, источник, флаг скачивания и флаг масштабирования. - `REQ-002` REQ-002 Результат работы выводится в машиночитаемом структурированном виде, пригодном для tool calling ИИ-агентом: перечень найденных изображений с источником, URL, форматом и фактическими размерами, а также однозначное различие между успехом, отсутствием подходящих изображений и ошибкой. - `REQ-003` REQ-003 Доступ к источникам бесплатный, без API-ключей, регистрации и иных учётных данных; поиск выполняется без настройки секретов. - `REQ-004` REQ-004 Источник изображений выбирается вызывающей стороной через параметр; схема допускает подключение нескольких источников, и в поставку входит как минимум один рабочий бесплатный источник; неизвестный источник даёт явную ошибку с перечнем доступных источников. - `REQ-005` REQ-005 Поиск выполняется по теме (текстовому запросу), задаваемой вызывающей стороной; количество возвращаемых результатов может быть ограничено вызывающей стороной. - `REQ-006` REQ-006 Вызывающая сторона задаёт желаемый размер изображения (ширина/высота); в результатах по каждому изображению указываются его фактические размеры. - `REQ-007` REQ-007 Формат изображения выбирается из начального набора png и ico; возвращаются только файлы запрошенного формата, а при отсутствии таких изображений у источника выдаётся явное сообщение, что изображений такого формата нет, отличимое от ошибки доступа к источнику. - `REQ-008` REQ-008 Возвращаются только изображения, размер которых не меньше желаемого по обоим измерениям; если у источника по теме нет изображений подходящего размера, выдаётся явное сообщение, что подходящих по размеру нет, отличимое от сообщения об отсутствии формата и от ошибки доступа. - `REQ-009` REQ-009 По флагу скачивания найденные изображения сохраняются в каталог, указанный вызывающей стороной, а в результате сообщаются пути сохранённых файлов. - `REQ-010` REQ-010 При наличии флага масштабирования изображения, доступные только в размере больше желаемого, уменьшаются до желаемого размера; без этого флага изображения сохраняются без изменения размеров. - `REQ-011` REQ-011 Утилита поставляется и запускается как обычный исполняемый процесс, без Docker и контейнеров. ## Artifacts _None recorded._ ## Delivery Requirements - `native_process` (requirements=['REQ-011']) ## External Inputs _None recorded._ ## Acceptance Criteria - `AC-001` AC-001 Для заданной темы утилита возвращает машиночитаемый список результатов, в каждом элементе есть URL, формат и фактические размеры; успешный поиск, отсутствие подходящих изображений и сбой различимы по коду завершения и структуре вывода. - `AC-002` AC-002 Поиск успешно выполняется в окружении, где не задано ни одного API-ключа или учётных данных. - `AC-003` AC-003 Указание источника в параметрах приводит к использованию соответствующего источника, и использованный источник явно отражён в выводе; неизвестный источник даёт явную ошибку с перечнем доступных источников. - `AC-004` AC-004 Запрос формата png возвращает только реальные png-файлы; запрос ico при отсутствии ico у источника даёт явное сообщение о том, что изображений такого формата нет, и это сообщение отличимо от сообщения об ошибке доступа к источнику. - `AC-005` AC-005 При запросе желаемого размера в выдаче присутствуют только изображения, размер которых не меньше желаемого по обоим измерениям, и для каждого указаны фактические размеры. - `AC-006` AC-006 Если по теме у источника есть только изображения меньше желаемого размера, вывод содержит явное сообщение, что подходящих по размеру нет, и это сообщение отличимо от сообщения об отсутствии формата и от ошибки доступа. - `AC-007` AC-007 При указании флага скачивания файлы физически сохранены в заданном каталоге, пути в выводе соответствуют существующим файлам, и файлы открываются как изображения заявленного формата. - `AC-008` AC-008 При наличии флага масштабирования изображение, найденное в размере больше желаемого, сохраняется с размерами, равными желаемым; без этого флага фактические размеры сохранённого файла совпадают с исходными. - `AC-009` AC-009 Утилита запускается как обычный исполняемый процесс без Docker и без контейнерной обвязки. - `AC-010` AC-010 Реальная проверка на известном результате: запрос по теме, для которой у выбранного источника заведомо есть изображения, возвращает непустой список с рабочими ссылками на файлы (проверка на живом источнике, а не только на синтетических данных). - `AC-011` AC-011 При запрещённом сетевом доступе к источнику утилита завершается явной ошибкой доступа и не выдаёт результат, выглядящий как успешный поиск. ## Out of Scope - `OOS-001` Генерация изображений и любые операции редактирования, кроме уменьшения до желаемого размера - `OOS-002` Форматы изображений вне начального набора png/ico - `OOS-003` Платные и требующие API-ключей источники изображений - `OOS-004` Запуск в Docker/контейнерах - `OOS-005` Графический интерфейс пользователя ## Unknowns / Risks - `UNK-001` Какой именно бесплатный источник реализуется первым и покрывает ли его API фильтрацию по размеру/формату или фильтрация выполняется на стороне клиента (влияет на объём загружаемых данных) - `UNK-002` Практическая доступность файлов формата ico у бесплатных источников: ожидаемо такие запросы будут часто возвращать сообщение об отсутствии формата - `UNK-003` Ограничения частоты запросов и требования к идентификации клиента (user agent) у выбранного бесплатного источника - `UNK-004` Каталог сохранения по умолчанию, если вызывающая сторона не задала его явно - `UNK-005` Как сообщать частичный успех скачивания, когда часть файлов сохранилась, а часть нет ## Workflow - Readiness: `ready_for_architecture` - Contract asset: `agent-product-contract.v1.json` - Contract SHA-256: `b7622222e96d133d4c82b5d716cb2963e8b786272d2735fe9033295141b75ba6` - Transcript: `https://git.p2prod.ru/platform/product-requests/issues/1` - Generated by: `product-manager-agent` # Architect plan comments <!-- architect-agent:plan mode=llm --> ## Architecture Plan ### Context Product request issue #1: a console (CLI) image search/download utility invoked by an AI agent via tool calling. Contract requirements REQ-001..REQ-011: parameters for topic, desired size, format (initial set png/ico), source, download flag and resize flag; machine-readable structured output distinguishing success / no-images-of-format / no-images-of-size / source-access error (AC-001, AC-011); free access without API keys or secrets (REQ-003, AC-002); pluggable source selection with explicit unknown-source error listing available sources (REQ-004, AC-003); only requested format returned and explicit "no images of this format" message distinct from access errors (REQ-007, AC-004); only images not smaller than the desired size in both dimensions, with actual dimensions reported (REQ-006, REQ-008, AC-005, AC-006); download into a caller-specified directory with reported paths (REQ-009, AC-007); downscale-only resizing behind a flag, unchanged dimensions without the flag (REQ-010, AC-008); live-source verification on a known topic (AC-010); delivered and run as a plain executable process with no Docker/containers (REQ-011, AC-009). Approved network access is Wikimedia Commons and Open ### Decision Shape: script_toolkit (Python 3, command_line runtime, cli interface, native_process delivery, repository_root placement). This is the narrowest catalog-template-backed shape that covers every resulting language, runtime, public interface and delivery form: the deliverable is one command-line program that speaks over argv/stdout, there is no HTTP server and no second language, and REQ-011/AC-009 forbid container delivery. 'file_io' is intentionally not declared as a separate public interface: writing downloaded files into the caller-specified directory (REQ-009) and reporting the resulting paths (REQ-002) is internal behavior of the CLI invocation, not an independent repository interface, and declaring it would leave the shape without a supported facade template. Facade: initialize (currently missing) at repository_root, since no product artifact fixes a component root. Implementation direction: a single Python CLI entry module parsed with argparse (topic, desired width/height, format png|ico, source, --count limit, --download, --output-dir, --resize), a small source-adapter registry (Wikimedia Commons MediaWiki API first, Openverse as a second adapter behind the same registry) so ### Constraints - Project shape is limited to script_toolkit/Python/command_line/cli/native_process at repository_root; do not add an HTTP service, a second language or container packaging. - Delivery must be a plain executable process (REQ-011, AC-009): no Dockerfile, compose file or container entrypoint. - Only free, credential-free sources; no API keys, tokens, registration or secret configuration may be required or read at runtime (REQ-003, OOS-003). - Only Wikimedia Commons and Openverse over HTTPS 443 (incl. subdomains) are approved network destinations; no other hosts and no public-download fallbacks. - Format support limited to png and ico (REQ-007, OOS-002); no other formats and no editing beyond downscaling (OOS-001). - Output must remain a single machine-readable JSON document with distinct status values and matching exit codes for success, no-format, no-size, access error and invalid request (REQ-002, AC-001, AC-011). - Filters must be applied on the client side to the actual downloaded/parsed image data, not trusted from source metadata alone, so reported format and dimensions are real. - Resizing may only downscale to the desired size and must be off by default (REQ-010, AC-008). ### Risks - UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes. - UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed. - UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior. - UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized. - UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics. - Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback. - Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results. - Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades. ### Team Lead Handoff - First prove the smallest end-to-end public path on the live source: run the CLI for a known topic against Wikimedia Commons requesting png, observe a non-empty JSON list with working URLs and real dimensions (AC-010), then confirm the same run with no API key/credential env vars set (AC-002). - Bounded check for UNK-001: issue one documented MediaWiki/Openverse search request and record whether size/mime filtering is available server-side and how many candidates must be fetched to satisfy the >= size rule; the decision between server-side parameters and client-side-only filtering (and any candidate cap) depends on that observation. - Bounded check for UNK-003: run a handful of sequential requests and record response codes, any 429 behaviour and whether a custom User-Agent is required; the retry/backoff design and whether a --count cap is enforced client-side depend on the result. - Bounded check for UNK-002: query an ico request against the chosen source and record whether the no-format status is produced while the source is reachable; this decides how the no-format message is worded and which exit code is paired with it. - Bounded check for Pillow availability: attempt prepare_environment with the declared manifest and record whether Pillow resolves from the internal catalog; the choice between Pillow-based ICO decode/resize and a reduced, explicitly recorded capability depends on that result. If it is missing, request operator publication; do not add public index fallbacks or credential changes. - Decide and document UNK-004 and UNK-005 with the product owner before finalizing REQ-009 output: default download directory behaviour and the status/exit code for partial download success. - All dependency changes must go through the manifests and lock files declared by the generated facade and Tool Backend prepare_environment; agents must not change package sources, credentials, network access or admission policy, and any policy exception requires human approval. - Preserve required coverage: every status branch (success, no-format, no-size, access error, invalid/unknown source) needs its own executed check and matching exit code, and aggregate exit 0 must not be treated as proof that the no-format and no-size outcomes work.
ai-team-lead added the role:developerstatus:draft-development labels 2026-11-02 22:44:50 +00:00
ai-dev added status:waiting-for-dependency and removed status:draft-development labels 2026-11-02 22:45:04 +00:00
ai-dev added auto:allowedstatus:ready-for-development and removed status:waiting-for-dependency labels 2026-11-03 00:11:45 +00:00
Member

Claimed by agent-dispatcher.

<!-- agent-dispatcher:lease token=8753cad0e9ee45f8a4c9942e644816d5 role=developer agent=developer-pool-1 expires_at=1793666365 --> Claimed by agent-dispatcher.
ai-dev added status:in-development and removed status:ready-for-development labels 2026-11-03 00:11:49 +00:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: projects/product-54354138-1#5