Skip to content

feat(preprocessing): declared step geometries, unconditional hflip, MCP recipe get and update - #810

Merged
JArmandoAnaya merged 5 commits into
mainfrom
feat/preprocessing-closeout-backend
Aug 26, 2026
Merged

feat(preprocessing): declared step geometries, unconditional hflip, MCP recipe get and update#810
JArmandoAnaya merged 5 commits into
mainfrom
feat/preprocessing-closeout-backend

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

Summary

The backend and docs half of the pre-processing epic's closeout (cf. #785): a step declares the geometries it transforms and the refusal reads that declaration, an hflip variant always mirrors, recipe read and update reach MCP, two stale comments go, and the driver guide, the grammar refusal and the tutorial's --recipe land in the docs. Part of the closeout of #785; the issue is closed by the companion frontend pull request.

What changed

  • feat(preprocessing): steps declare the geometries they transform. AUGMENT_GEOMETRIES in the kernel domain is the one table of what each augmentation can move, the exporter's supported_geometries convention; ResizeStep and AugmentStep read it back as supported_geometries (and expose name, what a refusal calls the step). The geometry transform consults the declaration for every step, on the base file and on each variant, and raises PreprocessingStepUnsupportedGeometry with the same step, geometry and asset_id fields. rot90 excludes polylines; hflip, brightness_contrast and resize transform everything. Tests: a table over ops × geometries, and two that narrow a declaration and watch the refusal follow it.
  • fix(preprocessing): an hflip variant always mirrors. hflip_applied read a seeded bit, so a variant could be a byte-identical copy of its source under a variant's name, the case rot90 already refuses by never drawing zero turns. The mirror is unconditional in the geometry transform and the Pillow driver; hflip_applied is removed (word-boundary grep clean), and the brightness, contrast and rot90 draws keep their seed words so nothing else re-rolls. Docs and the port docstring say so.
  • feat(mcp): recipe get and update tools. get_preprocessing_recipe and update_preprocessing_recipe, the latter through the same PreprocessingRecipeService.update the REST PUT uses, with new_name for a rename. The module docstring that argued against them is rewritten. Tests cover the round trip, the rename, the not-found, the name-taken and the grammar refusals. docs/content/mcp-tools.md is regenerated and the counts in mcp.md follow (58 by default, 62 in all).
  • chore(server): drop two stale comments on unreachable-error claims. The sentences saying no route raises AugmentationRequiresSplit and PreprocessingStepUnsupportedGeometry; the rule each comment carries stays.
  • docs(preprocessing): writing a driver, the grammar refusal, and the tutorial. A new docs/content/architecture/backend/preprocessing-drivers.md beside the provider guide, registered in the sidebar and the backend README table and linked from formats.md: the port, the entry-point TOML, instances not names, that every draw comes from the kernel seed helpers, the image-library rule, the byte promise, a smallest driver, and the admission rules tests/preprocessing/test_driver_registry.py enforces. The refusals table gains the grammar violation (422 VALIDATION_ERROR, the rule text as the message), and the tutorial's export step points at --recipe NAME.

openapi.json is unchanged: no wire or route docstring moved.

Found, not fixed

  • PreprocessingStepUnsupportedGeometry's docstring in kernel/errors.py still says "today's one case is rot90 over a polyline"; true, and left as it stands.
  • The step grammar is a closed Step union, so a third-party driver can only replace resize or augment, never add a kind; the guide says so rather than promising otherwise.
  • The export report's pillow_version field describes the built-in drivers only; a driver on another library would make it name the wrong thing. Noted in the guide.
  • The docs site build (check.sh docs) was not run here; the worktree has no docs/node_modules. The sidebar test in tests/scripts/docs_sidebar.test.mjs passes.

Test plan

  • uv run pytest tests/kernel/test_preprocessing_transform.py tests/kernel/test_preprocessing.py tests/kernel/test_export_seam.py tests/preprocessing — 139 passed
  • uv run pytest tests/server/test_preprocessing_recipes.py tests/cli/test_recipe*.py tests/mcp — green (373 passed in tests/mcp)
  • uv run pytest tests/server/test_errors.py — 31 passed
  • uv run ruff check src tests, uv run ruff format --check, uv run mypy src/visionset/kernel — clean
  • uv run python scripts/export_mcp_tools.py and uv run python scripts/export_openapi.py — the former committed, the latter a no-op
  • node --test tests/scripts/docs_sidebar.test.mjs — 4 passed
  • bash scripts/check.shcheck.sh: PASSED ran=python,frontend,generated,browser skipped=docs

@JArmandoAnaya
JArmandoAnaya force-pushed the feat/preprocessing-closeout-backend branch from 31539f7 to 5fa5d3c Compare August 26, 2026 14:11
Each recipe step reads its supported geometries from one table in the
kernel domain, the exporter's supported_geometries convention, and the
geometry transform refuses any manifest geometry outside that set. rot90
excludes polylines; hflip, brightness_contrast and resize transform every
geometry. The refusal keeps its step, geometry and asset_id fields.
hflip read a seeded bit and could emit a byte-identical copy of its source
under a variant's name, the case rot90 already refuses by never drawing zero
turns. The mirror is now unconditional in the geometry transform and the
Pillow driver; the brightness, contrast and rot90 draws keep their seed
positions, so no other variant re-rolls.
get_preprocessing_recipe reads one recipe by name and
update_preprocessing_recipe replaces its spec whole and renames it on
request, through the same service method the REST PUT uses, so recipe
CRUD is offered on REST, CLI and MCP alike. The tool reference is
regenerated and the counts in the MCP guide follow.
The export and compatibility routes raise AugmentationRequiresSplit and
PreprocessingStepUnsupportedGeometry through the recipe path, so the
sentences saying no route raises them were wrong; the rule each comment
carries stays.
…utorial

A guide to writing a pre-processing driver beside the provider guide: the
port, the entry-point group, that the kernel takes instances, that every
draw comes from the kernel's seed helpers, the image-library rule, and the
admission tests. The refusals table gains the grammar violation, and the
tutorial's export step points at --recipe.
@JArmandoAnaya
JArmandoAnaya force-pushed the feat/preprocessing-closeout-backend branch from 5fa5d3c to 75a14de Compare August 26, 2026 14:17
@JArmandoAnaya
JArmandoAnaya merged commit a4c3630 into main Aug 26, 2026
15 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the feat/preprocessing-closeout-backend branch August 26, 2026 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant