Confidence review
x-lt-confidence turns a form a model filled into a review. Each proposed value carries its score’s tranche, the form counts the tranches and the edits, and every changed answer shows what it was, while the form is worked and after it resolves.
| Token | Placement | Purpose |
|---|---|---|
x-lt-confidence | Schema root | The tranches, the input paths, and facets |
x-lt-confidence: false | Field | Leave this field out of the review |
The inputs
Section titled “The inputs”The workflow proposes values in envelope.formDefaults, which prefill the form as usual, and scores them in envelope.confidence, the same shape with numbers in [0, 1]:
await conditional<IntakeReviewV1>(signalId, { role: 'intake-verifier', envelope: { formDefaults: { applicant: { first_name: 'Jon', date_of_birth: '1987-03-04' }, account_type: 'individual' }, confidence: { applicant: { first_name: 0.52, date_of_birth: 0.58 }, account_type: 0.66 }, }, schemaVersion: 1,});Both are read in payload shape and mapped through x-lt-bind, so a field bound to applicant.first_name reads its proposal and its score from that path.
The token
Section titled “The token”Change a value in the preview and the field shows Edited; press it to see the proposal and restore it.
{ "x-lt-confidence": { "tranches": [ { "below": 0.6, "label": "Low", "tone": "error" }, { "below": 0.85, "label": "Check", "tone": "warning" } ] }, "properties": { "first_name": { "type": "string", "title": "First name", "x-lt-bind": "applicant.first_name" }, "last_name": { "type": "string", "title": "Last name", "x-lt-bind": "applicant.last_name" }, "date_of_birth": { "type": "string", "format": "date", "title": "Date of birth", "x-lt-bind": "applicant.date_of_birth" }, "account_type": { "type": "string", "title": "Account type", "enum": ["individual", "joint", "business"] } }}Submit the form to see what the workflow resumes with.
| Field | Meaning |
|---|---|
tranches | Any number of { below, label, tone }. A score falls into the first tranche whose below it is under; a score at or above every threshold is confident and shows plainly |
tranches[].below | A threshold in (0, 1] |
tranches[].label | The tranche’s name, shown beside each field and in the review key |
tranches[].tone | error, warning or info; defaults to warning |
scores | The context path to the scores. Defaults to envelope.confidence |
proposed | The context path to the proposals. Defaults to envelope.formDefaults |
facets | true stamps a review summary onto the row’s metadata when it resolves |
"x-lt-confidence": true uses the default tranches: Low under 0.6, Check under 0.85. A field opts out with "x-lt-confidence": false; display-only widgets stay out of the review.
What the form shows
Section titled “What the form shows”- The tranche, on the field. The control’s rule takes the tranche tone, and a line under it names the tranche and the score:
Low · 52%. Focus still takes the accent, and a validation error keeps its own rule. - The review key, above the fields. One entry per tranche with its count, and Edited with the changed answers out of the proposed ones. Each entry walks its fields: press Low and the next low-confidence field scrolls into view and takes focus.
- What it was, while editing. Once an answer differs from its proposal, the field shows Edited. Press it to see the proposed value and Restore it.
- What it became, after submit. A locked or resolved form shows each changed field as
Was Jon → John, beside its tranche.
The proposal comes from the envelope, which the resolve leaves untouched, and the answer from the stored resolver payload, so a resolved row shows the same review for as long as it exists. Answers compare as values: an empty string and a missing answer are equal, "42" equals 42, text compares by its words (surrounding and repeated whitespace is the same text), and object key order is ignored. The answer is stored exactly as submitted.
Beside the document
Section titled “Beside the document”A review usually sits beside the document it checks. Name the files on the row, show each with the document widget, and set "x-lt-layout": "split":
{ "x-lt-layout": "split", "x-lt-confidence": true, "properties": { "application": { "type": "string", "title": "Application", "x-lt-widget": "document", "x-lt-source": "file.application" }, "first_name": { "type": "string", "title": "First name", "x-lt-bind": "applicant.first_name" }, "last_name": { "type": "string", "title": "Last name", "x-lt-bind": "applicant.last_name" }, "date_of_birth": { "type": "string", "format": "date", "title": "Date of birth", "x-lt-bind": "applicant.date_of_birth" }, "account_type": { "type": "string", "title": "Account type", "enum": ["individual", "joint", "business"] } }}Submit the form to see what the workflow resumes with.
Review facets
Section titled “Review facets”With "facets": true, the server summarizes each review when the row resolves and merges the summary into its metadata, inside the same guarded update that resolves it:
| Key | Value |
|---|---|
review_outcome | corrected when any shown answer differs from its proposal, else accepted |
review_changed | How many shown answers differ, as a string ("3") |
review_worst | The lowest tranche any shown field fell into ("Low"); absent when every score cleared |
The counts cover the fields the form shows for the submitted answer, the same set the review key counts. The server computes them from the role’s schema, so an answer through the form, the API or an MCP tool reports the same way, and they win over a caller’s metadata of the same name.
The facets need enforce_schema: true on the role. Every single-row resolve stamps them; a bulk resolve applies one payload to many rows and leaves them off, which keeps bulk approvals apart from reviewed ones. Group by them with the resolved measure for trends per model version: see Document review.
In the workflow
Section titled “In the workflow”The same rules are exported for workflow and agent code:
import { differsFromProposal } from '@hotmeshio/long-tail';
const corrections = Object.entries(flat(proposed)) .filter(([path, value]) => differsFromProposal(value, get(review, path)));readConfidenceSpec, buildFormReview, summarizeReview and buildReviewFacets are exported beside it.
