Skip to main content
Approvals pause a workflow for a human decision. An approval definition is a versioned state machine; each run records its current state, open tasks, and append-only transitions. Advancement and timeout checks use the existing durable job queue. Use Automations for deterministic event-driven actions. Use approvals when a person’s explicit choice controls what happens next. Definitions and runs belong to one filing system, including documentless rescan proposals; builtin document-change/rescan definitions exist per system. Slug/version identity, deduplication, sweeping and eligibility are system-scoped. Task assignment never grants entry: members need the run’s system membership and, for document-bound work, document visibility. Applying a suggestion cannot attach foreign-system metadata or transfer a document. Instance administrator access remains subject to an explicit request or token system boundary.

Model

  • A definition stores a versioned JSON state machine under a stable slug.
  • A run binds one definition version to a document and current state.
  • A task asks one user or resolved role to choose from declared options.
  • A transition records the previous state, next state, trigger, actor, and time.
Runs are running, done, failed, or cancelled. Tasks are open, claimed, resolved, or expired.

Definition

Validation requires a real start state, valid state names, known state kinds, valid transition targets, and a mapping for every approval choice. Assignees use user:<id>, document_owner, or a registered role:<name> resolver. document_owner resolves when a document-bound run creates its task. The shipped role:admin resolver assigns a shared task visible to administrators. Built-in state kinds are:
  • system: emits a routing event without creating a task
  • approve: creates a human task and waits for a choice or timeout
  • end: completes the run and expires remaining tasks
Additional kinds can be registered in a custom distribution through Engine.RegisterHandler. Handlers can return a transactional effect with their routing event. Suchi runs that effect in the same transaction as the transition, which keeps a human-approved write retry-safe when the durable job is redelivered.

API flow

Register the example under invoice-approval from an administrator’s browser or OIDC session:
Then start it:
$TOKEN needs documents:write and change access to document 17. The assignee resolves the resulting task from the Approvals screen or API. A resolution enqueues the next advancement; the HTTP request does not run the whole state machine inline.

Timeouts and recovery

Entering a state with timeout_sec records a deadline. A recurring durable timeout sweep enqueues a timeout advancement for due runs and expires their open tasks. The definition must map timeout when timeout behavior is desired. Interrupted jobs are reclaimed on startup. Each queued advancement and task is bound to one visit to a state; stale retries cannot replay a choice on a later visit or recreate a resolved task. Effects and task creation recheck that revision inside the writer transaction. Cancellation records a transition and expires tasks; accepted decisions clear their deadline before a later timeout sweep can act. Accepting a decision or timeout increments the run revision immediately, so delayed entry work cannot create another task or apply an effect while advancement waits. The beta.2 upgrade preserves pending decisions only when retained entry jobs and the resolved task prove their state. Initial-state timeouts can resume; later-state timeouts have ambiguous origins in the old implementation. Missing entry history or ambiguous events leave affected jobs dead with a recovery message, preserving the current review. Inspect the run and resolve a current task, or cancel and restart a stalled run. Retrying an unbound old job cannot authorize it. Run and task IDs are retained and no longer reused after deletion. The run allocator also skips IDs retained in old jobs. Purged task IDs without pre-upgrade allocation history cannot be reconstructed. Approval jobs appear in /api/tasks/; filter by kind=approval: when investigating a stalled run. Application logs use component=approvals.

Document suggestions

Archive matching and low-confidence LLM title classification use the shipped document-change definition. Each suggestion becomes an approval assigned to the document owner with its field, proposed value, confidence, source, and supporting document IDs stored in the run variables. Applying a suggestion changes the document through the approval transition; rejecting it only closes the run. Repeated classifiers do not open a duplicate active review for the same document, field, and value. Classification decisions are independent per field. A confident category can file a document immediately while lower-confidence correspondent or tag suggestions remain in Approvals. The Approvals screen shows the current filing category alongside the exact proposed action so those reviews are not mistaken for a second filing decision. If a pending suggestion becomes true before it is reviewed, the existing approval sweep closes it as system:satisfied and records document.suggestion_satisfied in the audit log. It does not linger as an actionable approval or disappear without history. If a document has instead been filed into a different non-Inbox category, the sweep dismisses its obsolete filing proposal as system:superseded, with a document.suggestion_superseded audit event. Its existing filing is unchanged. Inbox documents keep their pending filing proposals. The sweep runs every 30 seconds through the job queue; an ingestion backlog can delay it. This remains the extension pattern for future action workflows: a producer starts an approval in its existing transaction, and a typed handler performs the approved write. Reviewable extracted facts use the deliberately separate document_intelligence ledger because they are bulk metadata decisions, not state-machine runs.

Review dates

Start with Document dates for the complete user workflow. The Approvals screen hosts pending document_intelligence candidates. Selection works per date, source document, or visible result set. Dates and workflow approvals share the same card grid. More than two groups use two desktop columns and one mobile column; one or two groups stay in a compact single column. The selected-date action bar stays above the list while scrolling. One bounded API call adds or rejects the selected IDs. This review does not create approval definitions, runs, transitions, or one task row per date. See Document dates: Automatic and reviewed dates for the threshold, review, and rescan rules.

Rescan proposals

Suchi ships a rescan-proposal definition. When a code, extraction schema, or prompt version makes stored processing results stale, Suchi creates one admin review task per affected pipeline kind. The choices are:
  • rescan every stale document
  • rescan a random sample of 20 when more than 20 documents match
  • dismiss the proposal
Configuration changes alone do not create a proposal or automatically rescan the archive. LLM documents that have never completed classification are also excluded from automatic upgrade proposals. Documents already queued for post-ingest work, already surfaced as failed jobs, or waiting for a PDF password do not create a second rescan prompt. Operators can always select documents and run an explicit rescan.

Current limits

  • A run has one current state; parallel branches are not supported.
  • Definitions are managed as JSON through the API rather than a visual editor or watched directory.
  • A role:admin task is shared by all administrators until one resolves it; assignment is not round-robin.
See API for request and error payloads and Pipeline versions for stale-result semantics.