feat: "Approve and start" and "Complete and promote" as one action on UI, CLI and MCP - #804
Merged
Merged
Conversation
JArmandoAnaya
force-pushed
the
feat/composed-transitions
branch
from
August 26, 2026 12:53
c6fd667 to
a478d5b
Compare
Each flag is the next lifecycle command made in the same run: approve then
start, complete then promote, and for ingest approve as one job then start.
No transition is added; start needs only approved and promote only completed,
so the second call is legal whenever the first succeeded. Each step commits on
its own, and a refused second step prints the first step's line, the refusal
as the single-step command prints it, and a line naming the step that refused
and the state the batch is in.
Plain output reports both outcomes and keeps the batch id alone on stdout.
With --json, approve --start and ingest --start print the started batch;
complete --promote prints {"batch": ..., "promoted": ...}, the closed batch
beside the page of assets that entered the dataset.
approve_batch(start=True) is start_batch in the same call and complete_batch(promote=True) is promote_batch in the same call. Each answer reports what it did: started says whether the batch was opened, promoted counts the assets that entered the dataset, so a move is never an invisible side effect. Approval and completion each commit before the next step is attempted, and a refusal leaves the batch where the first step put it. The tool reference is regenerated from the served listing.
The CLI reference, the MCP guide, the batches page and the tutorial name approve --start, complete --promote and ingest --start, and the start and promote parameters of the MCP tools. The tutorial opens a batch with the one-command form and keeps the two-command walk as the explicit variant.
… each Two lifecycle steps behind one control, offered on the first step's declaration: Approve and start on a draft row of the batch table and on the ingest run card once a run settles, where it is the card's filled control and Open batch steps down; Complete and promote in the gallery header beside Complete, withheld the same way while frames are outstanding. Each sends the two requests in order and stops where the kernel stops it, showing the first step's outcome as a line and a second-step refusal beneath it. Approve and start reads the project's schema itself, since approval pins one and the batch's declaration cannot say whether there is one to pin; without a schema the row keeps its controls and the run card says what approving needs and where to get it. A control keeps its own record of having been pressed, so the line survives the batch's declaration moving on.
JArmandoAnaya
force-pushed
the
feat/composed-transitions
branch
from
August 26, 2026 12:59
a478d5b to
ad1d5aa
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.
Closes #790
What changed
Two pairs of lifecycle steps are offered as one action on every surface, without adding a transition to the kernel or a capability to the wire. Each composed action is two sequential calls behind one control, offered on the first step's declaration; if the second step refuses, the batch stays where the first step put it and the surface says so.
CLI.
visionset batch approve --start,visionset batch complete --promoteandvisionset ingest --start(ingest, approve as one job, start). Each performs step one, then step two on success, and prints both outcomes. A refusal of a later step exits non-zero, prints the ordinary typed refusal, and names the step and the batch's actual state, so nobody guesses.--jsonprints the final batch document;complete --promote --jsonprints the batch document and the promoted page underbatchandpromoted, the shapeingest --jsonalready uses for a hand-built composite.MCP.
approve_batchgainsstart: bool = Falseand reportsstartedin its payload;complete_batchgainspromote: bool = Falseand reportspromoted(a count). Nothing a tool does is an invisible side effect. Theapprove_batchdescription no longer tells the caller to invokestart_batchnext; it names the parameter.docs/content/mcp-tools.mdis regenerated from the served listing, and the capability reachability check is unchanged.UI. Approve and start sits on a draft's row in the batch table, secondary like every row action, beside Approve (whose dialog remains the way to cut a batch into several jobs), and on the ingest run card once a run settles, where it is the card's one filled control and Open batch steps down to secondary. Complete and promote sits in the gallery header beside Complete, withheld the same way while any frame is still to do, and says what the press moved in the sentence Promote already uses. Approve and start is offered only while the project has an active schema: approval pins one, and the batch's
allowed_actionscannot say whether there is one to pin, because that is a fact about the project rather than a state of the batch. Without one, the row keeps its controls and the run card says in words what approving needs, with the way to the schema section beside it; only a schema that does not exist counts as none — any other failure of that read leaves the card as it was.Every composed control keeps the first step's outcome on screen as a line (Approved against v3, Completed, finishing 1 job) and renders a second-step refusal beneath it through the shared vocabulary, never in its place. The control keeps its own record of having been pressed, because the batch's declaration moves on after the first step and the control would otherwise unmount with it, taking the line and the refusal along.
Docs.
docs/content/cli.md,mcp.mdandbatches.mddescribe the composed forms;tutorial.md's approve-then-start step becomes one command, with the two-command walk kept as the explicit variant, and its finish becomescomplete --promote;ui.mdgains Two steps as one. The sitemap is unchanged: no route, tab or entry point moved.Capabilities checklist
Per control: a refusal renders through
refusalProseandFieldError; success renders as the line and, for promotion, the summary and the link to the dataset; the rejected promise is the mutation's ownisError; the hooks already invalidate the batch, its jobs, the batch list, the project and the dataset after each step. No legality is computed on the client — the controls are gated on the wire'sapproveandcompletedeclarations. The schema pre-read is the one condition the declaration cannot carry, and the no-schema card explains the absence rather than hiding it.Revoked guards
None. Every existing test passes unchanged.
Test plan
scripts/check.shin full on the branch before the rebase: annotator 1071, ui-core 1356, app 11 tests; frontend lint; OpenAPI, generated-client and MCP tool-reference drift; version sync;annotator + app e2e (chromium)282 passed;browser cycle, real server (chromium)1 passed. The docs site by hand: 48 pages, 4423 internal links resolve; thedocs_links,design_tokensandwire_rostersgates 25/25.2d6d505(one import-line conflict inIngestScreen.tsx): whole-treeruff checkandpnpm -r lintclean; ui-core screens 749 passed;tests/cli tests/mcp tests/architecture tests/server1802 passed; the gallery specs and the real-server cycle re-run green.draft, exit non-zero, step named) and the idempotent zero-promoted outcome; a gallery e2e scenario pressing Complete and promote (job, batch, promotion, in order); cycle assertions that the run card's filled control is the composed step over a project with a schema, that a draft row offers it secondary, and that the header withholds it while frames are outstanding.A baseline flake, not this branch's
The first full
check.shpass failedtests/scripts/test_cooldown_lockfile.py::test_an_interrupted_first_pass_changes_nothingand::test_an_interruption_during_the_snapshot_changes_nothingwithassert 0 == 130, the same two that failed the first pass on #794's branch. Nothing here touchesscripts/cooldown.shortests/scripts/. Both pass in isolation onmainand on the branch, the file passes under the configured parallelism repeatedly, and the python step re-run ascheck.shruns it answers4497 passed, 33 skipped. They time a signal against a liveuv addand lose the race on a cold first run.Also fixed
Nothing beyond the scope above.