feat(preprocessing): declared step geometries, unconditional hflip, MCP recipe get and update - #810
Merged
Merged
Conversation
JArmandoAnaya
force-pushed
the
feat/preprocessing-closeout-backend
branch
from
August 26, 2026 14:11
31539f7 to
5fa5d3c
Compare
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
force-pushed
the
feat/preprocessing-closeout-backend
branch
from
August 26, 2026 14:17
5fa5d3c to
75a14de
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
hflipvariant always mirrors, recipe read and update reach MCP, two stale comments go, and the driver guide, the grammar refusal and the tutorial's--recipeland in the docs. Part of the closeout of #785; the issue is closed by the companion frontend pull request.What changed
AUGMENT_GEOMETRIESin the kernel domain is the one table of what each augmentation can move, the exporter'ssupported_geometriesconvention;ResizeStepandAugmentStepread it back assupported_geometries(and exposename, what a refusal calls the step). The geometry transform consults the declaration for every step, on the base file and on each variant, and raisesPreprocessingStepUnsupportedGeometrywith the samestep,geometryandasset_idfields.rot90excludes polylines;hflip,brightness_contrastand resize transform everything. Tests: a table over ops × geometries, and two that narrow a declaration and watch the refusal follow it.hflip_appliedread a seeded bit, so a variant could be a byte-identical copy of its source under a variant's name, the caserot90already refuses by never drawing zero turns. The mirror is unconditional in the geometry transform and the Pillow driver;hflip_appliedis 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.get_preprocessing_recipeandupdate_preprocessing_recipe, the latter through the samePreprocessingRecipeService.updatethe RESTPUTuses, withnew_namefor 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.mdis regenerated and the counts inmcp.mdfollow (58 by default, 62 in all).AugmentationRequiresSplitandPreprocessingStepUnsupportedGeometry; the rule each comment carries stays.docs/content/architecture/backend/preprocessing-drivers.mdbeside the provider guide, registered in the sidebar and the backend README table and linked fromformats.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 rulestests/preprocessing/test_driver_registry.pyenforces. The refusals table gains the grammar violation (422VALIDATION_ERROR, the rule text as the message), and the tutorial's export step points at--recipe NAME.openapi.jsonis unchanged: no wire or route docstring moved.Found, not fixed
PreprocessingStepUnsupportedGeometry's docstring inkernel/errors.pystill says "today's one case is rot90 over a polyline"; true, and left as it stands.Stepunion, so a third-party driver can only replaceresizeoraugment, never add a kind; the guide says so rather than promising otherwise.pillow_versionfield describes the built-in drivers only; a driver on another library would make it name the wrong thing. Noted in the guide.check.sh docs) was not run here; the worktree has nodocs/node_modules. The sidebar test intests/scripts/docs_sidebar.test.mjspasses.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 passeduv run pytest tests/server/test_preprocessing_recipes.py tests/cli/test_recipe*.py tests/mcp— green (373 passed intests/mcp)uv run pytest tests/server/test_errors.py— 31 passeduv run ruff check src tests,uv run ruff format --check,uv run mypy src/visionset/kernel— cleanuv run python scripts/export_mcp_tools.pyanduv run python scripts/export_openapi.py— the former committed, the latter a no-opnode --test tests/scripts/docs_sidebar.test.mjs— 4 passedbash scripts/check.sh—check.sh: PASSED ran=python,frontend,generated,browser skipped=docs