Skip to content

feat: the export-target catalog on every surface, and target beside format on export - #795

Merged
JArmandoAnaya merged 5 commits into
mainfrom
feat/targets-t3-catalog
Aug 26, 2026
Merged

feat: the export-target catalog on every surface, and target beside format on export#795
JArmandoAnaya merged 5 commits into
mainfrom
feat/targets-t3-catalog

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

Summary

The export-target catalog reaches every surface, and an export can be addressed to the model it will train rather than to a format. Position 3 of the export-targets epic (#784): T1 declared targets on the Exporter port and T2 shipped the two dialects; this phase serves the derived catalog and threads a target through compatibility and export.

Kernel and wire. ExportCompatibility and ExportResult record target, null when the release was judged against the format alone. check_export, require_export_consent and export take a target keyword. An export addressed to a target hands the plugin the manifest with every annotation the target does not carry removed, so the drop the report promises is what the output holds; the Exporter port is unchanged. Task is an open vocabulary, because it travels only as a target's task list. visionset.wire gains export_target, export_targets and preprocessing_hints; export_format gains targets.

REST. GET /export-targets serves ExportTargetPage (name, label, family, format, tasks, geometries, hints). FormatOut.targets names each format's own. POST /releases/{id}/export and GET /releases/{id}/export-compatibility take target as a query alias beside format, exactly one of the two; both or neither is a 422 VALIDATION_ERROR with loc: ["query"]. The export job's payload and result carry target and the resolved format. Route docstrings enumerate EXPORT_TARGET_NOT_FOUND and EXPORT_TARGET_CONFLICT; openapi.json and the generated client are regenerated.

CLI. visionset export --target yolo11; --format is kept; both or neither is a usage error at exit 2. --format yolo prints a deprecation line on stderr and continues. visionset target list prints the catalog without opening a workspace, and --json is the wire.

MCP. export_release and check_export take target or format, never both; list_export_targets is the catalog. The tool reference is regenerated.

Docs. The target table in docs/content/releases.md is generated from the catalog by scripts/export_target_catalog.py, with --check wired into check.sh, CI and a test the way the MCP tool reference is. The release, CLI, MCP, API and changelog prose gain targets, the target-narrowing rule and the task-derivation rule.

The UI still exports by format; the dialog's target select is the next phase of the epic. The jsdom format stub gains the targets field the contract now requires so the frontend build stays green.

Decisions taken here, for review

  • family is a plain string, not an open enum. The repository's open-vocabulary gate (test_a_vocabulary_is_open_exactly_when_its_shape_allows_it) admits the marker only where a value is referenced solely as an array item; family is a scalar per row, so marking it would fail the gate. A new family therefore arrives as a new string. tasks is marked open as specified.
  • The catalog is a page, not a bare array. docs/content/api.md and wire.page hold that a collection is {items, total} and never an array, so GET /export-targets answers ExportTargetPage.
  • A target narrows the manifest in the service. The port has no target parameter and none was added; without the narrowing, a yolov10 export of a release holding polygons would write a segment layout while its report said the polygons were dropped.
  • visionset target list, following the CLI's noun-group convention (format list, release list, token list).

Found, not fixed

  • tests/formats/test_report_agreement.py pins that the ultralytics dialect's task derivation drops a tag beside a located label while the declaration calls it supported; a target-addressed export does not change that pinned shape.
  • The archive of a target-addressed export lands under <workspace>/exports/<release_id>/<format>/, so two targets of one format overwrite each other's archive the way two exports of one format already did.

Stack

Position 3 of the export-targets stack (#784); based on feat/targets-t2-dialects (PR #792).

Checks

Targeted while iterating: uv run pytest tests/server tests/cli tests/mcp tests/jobs tests/architecture tests/kernel tests/formats, uv run lint-imports, uv run mypy src/visionset, uv run ruff check ., uv run ruff format ., uv run python scripts/export_openapi.py, pnpm generate:client, uv run python scripts/export_mcp_tools.py --check, uv run python scripts/export_target_catalog.py --check, pnpm -r build && pnpm -r test under Node 24.

Full gate on the final tree:

check.sh: PASSED  ran=python,frontend,generated,browser  skipped=docs
check.sh: PASSED  ran=docs  skipped=python,frontend,generated,browser

@JArmandoAnaya
JArmandoAnaya force-pushed the feat/targets-t2-dialects branch from 0d9fc5c to c780827 Compare August 26, 2026 11:20
Base automatically changed from feat/targets-t2-dialects to main August 26, 2026 11:27
…only what the target accepts

The compatibility report and the export result gain `target`, null when the
release was judged against the format alone. `check_export`,
`require_export_consent` and `export` take a `target` keyword; an export
addressed to one hands the plugin the manifest with every annotation the
target does not carry removed, so the drop the report promises is what the
output holds without the Exporter port learning a new parameter. `Task` is an
open vocabulary, since it travels only as a target's task list.

`visionset.wire` gains `export_target`, `export_targets` and
`preprocessing_hints`, `export_format` gains `targets`, and the server
models gain `ExportTargetOut`, `ExportTargetPage` and
`PreprocessingHintsOut` with the JSON-contract pairs that hold them equal.
Part of the export-targets epic (#784).
…export

`GET /export-targets` serves the catalog derived from the installed formats;
`FormatOut.targets` names each format's own. `POST /releases/{id}/export`
and `GET /releases/{id}/export-compatibility` take `target` as a query alias
beside `format`, exactly one of the two, both or neither refused as a 422
VALIDATION_ERROR with `loc: ["query"]`. The export job's payload and result
carry `target` and the resolved `format`. Route docstrings enumerate the
target refusals, openapi.json and the generated client are regenerated, and
the jsdom format stub gains the field the contract now requires.
Part of the export-targets epic (#784).
…ionset target list

`visionset export` takes `--target` beside `--format`, exactly one of the
two at exit 2 otherwise; a format reached through its former name prints a
deprecation line on stderr and continues. `visionset target list` prints the
catalog without opening a workspace, and `--json` is the wire.
Part of the export-targets epic (#784).
…lease and check_export

Both tools take `target` or `format`, never both, refused in the ordinary
envelope; `list_export_targets` is the catalog every other surface renders.
The tool reference is regenerated. Part of the export-targets epic (#784).
… drift gate

`scripts/export_target_catalog.py` writes the table between two markers in
docs/content/releases.md and `--check` fails when it is stale, wired into
check.sh, CI and a test the way the MCP tool reference is. The release, CLI
and changelog prose gain targets, the target-narrowing rule and the
task-derivation rule. Part of the export-targets epic (#784).
@JArmandoAnaya
JArmandoAnaya force-pushed the feat/targets-t3-catalog branch from b38157d to 1595713 Compare August 26, 2026 11:27
@JArmandoAnaya
JArmandoAnaya merged commit aeff95f into main Aug 26, 2026
15 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the feat/targets-t3-catalog branch August 26, 2026 11:33
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