Repository navigation
Conversation
route(human = True) asks a person through the controller. The executor opens the route's request and parks it: tasks that do not depend on the route keep dispatching, and the route settles when the request is answered (labels plus the decision record), expires (every question uncertain), or the run halts. The request carries the evidence the approver sees: dependency outputs and captured files, spend and ceilings, the tasks each answer starts, and an optional review template rendered with every value escaped for CommonMark. The run reaches the controller on its ingest surface with the pod's ingest credential; `human` is available exactly when that surface is. Contract 1.15.0 adds the request types and the decision_wait event. The RFC amendment specifies the human decider, its evidence, and run:approve. Assisted-by: Claude
The run opens and polls requests on its pod ingest surface; a local run gets a credential minted at spawn for its local-<run> pod name, revoked when the run completes. A person allowed run:approve lists open requests, reads one with its evidence, and answers it against the evidence digest; the first answer wins, a repeat is acknowledged, and an accepted answer is audited in the same transaction. Requests still open when their run completes are withdrawn. run:approve defaults to the principal the run is attributed to and a maintainer of an owning team, and a run principal is forbidden it. Assisted-by: Claude
Approvals lists the open requests the signed-in user may answer, and /decisions/:id shows one: the rendered review, each dependency's output and files (images, CSV, Markdown, JSON, and HTML or SVG in a sandboxed frame with no network), the tasks each answer starts, and the answer controls. The shell raises a browser notification when a request the user may answer opens; clicking it opens the request. The decision DTOs take a Decision prefix: utoipa keeps the last schema registered under a name, so EvidenceFileDto had silently replaced the task-evidence schema. examples/human-gate holds a priced training launch for approval and runs locally against `just controller-local`. Assisted-by: Claude
A human-decided route can now ask a choice that takes several labels (`choice(multiple = True)`) and a pick whose options are a list a dependency produced (`pick(source = plan.nodes)`). Picked values land under the question id as a string list, so `over = gate.nodes` fans out over what the approver chose. Models and output deciders still answer one label; validation refuses picks and multi-select on them, a `when` naming a pick, and a question named `decision`. Answers are a list of values per question on the wire and in the store. The controller and the engine both refuse values a question does not offer, repeats, and more than one value on a single-answer question. Run-end cleanup no longer marks an already-expired request withdrawn; expiry is computed on read, so the row still said open. The decision store returns typed errors instead of anyhow::bail. The UI gets a root error boundary and one around the routed page, so a page that throws while rendering shows the error and a reload button instead of a blank window.
|
Docs preview for this PR is built and attached as the Download Rebuilt for 7370dbb. |
decide now works on plain inputs (each dependency's status and output, a captured-file lookup) and returns a Settled value; exec builds those inputs and turns Settled into a TaskResult. The modgraph check forbids the cycle.
runs::ingest_drop merged decisions::ingest_routes while decisions reads IngestState from it, a module cycle the modgraph check refuses. The server now merges both routers on the shared ingest state.
Resolves the overlap with the OpenAI decider (#226): - QuestionKind keeps Score beside Choice { multiple } and Pick; Answer carries score, asked_as and labels. A person's score answer records its level position. - The broker's new decide module refuses pick questions; plan validation already keeps them off model routes. - needs = "decision" replaces "systemone" in the route checks. - Routes may now map over a list, but a human route may not: one request per route. A human route may not declare files either; its evidence already carries them. - The runner's captured_file hook is main's, keyed by producer name. - CONTRACT_VERSION 1.17.0; the decision tables move to migration 0055.
This branch has not been deployed
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.
A route can now be decided by a person:
route(human = True, review = "...", timeout = "20m"). The engine opens a decision request with the controller carrying the evidence (dependency outputs, declared files, spend, what each answer starts, a rendered review), parks the route while independent tasks keep running, and polls until someone allowedrun:approveanswers or the request expires. Expiry answersuncertain, which the author routes like any other label.The controller holds requests (one per run and route, digest-bound answers, audited), lists them on Approvals, and renders the evidence page with sandboxed HTML/SVG visualizations, Markdown, CSV and JSON. The web UI raises a browser notification when a request opens. Local runs authenticate with a per-run token.
Questions can be single choice, multi-select, or a pick from a list a dependency produced;
over = gate.nodesfans out over the picked values.examples/human-gateruns the whole flow on a laptop againstjust controller-local.The UI also gains an error boundary, so a page that throws shows the error instead of a blank window.
Changelog: Added: routes decided by a person, answered from the controller UI with the evidence, review and visualizations shown inline, and a browser notification when one opens