Skip to main content
Approvals pause a workflow for a human decision. A definition describes the allowed steps; each run records its current step, open tasks, and decision history. Background processing advances the next step and checks timeouts. 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.

Review-first mode

Choose Review first under Application mode to require review of inferred dates, model metadata, and local archive matches. Explicit rules written by a user remain independent. Suchi checks the current document, matching text, field generations, access, and reviewer credentials before recording or applying a decision.

Reviewing suggestions

The Approvals screen uses the same centered workspace card as Automations, Calendar, and Views. Its header keeps the page description, refresh action, and Show suggestion groups control together. Tabs below it show one kind of work at a time: All, Tags, Filing and Fields for metadata suggestions, which All counts, then Dates, and Decisions when workflow approvals are waiting. Administrators also get a Processing issues tab, set apart at the right end, when processing has failed. It names each affected document and offers Retry all when there is more than one issue. The open tab is kept in the address (#/tasks?tab=issues), so the Dashboard’s Failed jobs card opens Processing issues directly. When there are no metadata suggestions and no tab is named, the screen opens on the first tab with work. The workspace is capped at 1,400 pixels so the change sentence and its actions remain connected on very wide displays. The suggestion tabs open with one By document table, keeping each document’s current and proposed values together. Each document is one block: a small thumbnail beside its title and its suggestions, with a hairline only between documents. Each decision reads left to right as one change: the struck current value, an arrow, and the emphasized new value. An added tag reads + tag because it replaces nothing, in both projections. Rows share fixed action, change, reason, similar-document, and decision columns so different suggestion types retain the same edges. The reason is a quiet chip; supporting documents use a compact n similar disclosure. Choose Show suggestion groups to open a 400-pixel sidecar inside the same workspace card. The header control becomes Hide suggestion groups without moving, and the By document and By suggestion captions appear only while both projections are visible. Suggestion groups follow the document order: each group appears where its first document does and lists its documents in that order, so both projections read top to bottom together. Each projection shows at most 100 entries and states how many remain; settling visible entries brings the next queued entries into view. Long document names in a group are shortened so each document number stays visible. On wide screens the suggestion tabs fit the window: the header, tabs and both captions stay in place while each projection scrolls on its own. On narrower screens the sidecar stacks after the document table and the page scrolls as one. Applying or dismissing a decision updates both views immediately, and the item fades out of both at once (instantly when reduced motion is requested). While both projections are open, pointing at or focusing a suggestion group tints its document cards, also marking the linked decisions in a document that has several; pointing at a document tints its groups. Side by side, when no tinted entry is visible, the other projection scrolls the first one level with the entry you point at, so moving straight across lands on it. It waits until the pointer rests for about 300 milliseconds, so sweeping across one projection toward an entry does not scroll the other; keyboard focus scrolls at once. The link icon in the By suggestion caption states the same relationship for screen readers and on hover. Each decision row has its own dismiss and approve controls; documents with several decisions also offer Approve all and Dismiss all beside the title. Suggestion cards apply or dismiss the grouped decision for every listed document, as Apply to all n and Dismiss all n, or Approve and Dismiss when the group holds one document. Expand a grouped card’s document list before a bulk action when you need to inspect every affected item. A partially failed bulk action removes only completed decisions, keeps failures visible, and requires a refresh before retrying.

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. A live browser/OIDC session or an API token with documents:write may resolve routine reviews. The writer transaction reloads the user, token binding and token scopes before accepting the decision. 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. GET /api/tasks/?include=approvals remains a generic mixed workflow feed. Clients may render only the approval definitions and fields they understand; unknown rows stay available to other clients and the web application.

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 same sweep cancels document-change reviews whose bound source, field, destination or access state is no longer valid. 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. Upgrading an archive created before v0.1.0 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, model metadata, detected-language suggestions, and fixed metadata actions selected by a classifier-backed automation question use the shipped document-change definition when review is required. The task is assigned to the document owner. By default, Apply when confident lets eligible model and local archive changes apply automatically. Choose Review first to check every valid inferred change, even at 100% model confidence. Below-threshold or otherwise review-required changes still appear here. A document row states the current-to-proposed change once, followed by its reason chip and any supporting-document disclosure. How this was suggested expands model confidence and who suggested it on date-review cards. An automation-question card names the automation as the reason for its proposed fixed metadata effect, not the discarded question/answer transcript. Companion presents title, filing-category and tag suggestions from this same feed; other document-change fields, including typed custom fields, remain available in the web review surface. A title proposal is eligible only while the current title is automatically owned. Accepting it makes the resulting title human-owned. A person renaming the document, or a rule assigning a title before the queued effect runs, invalidates the proposal rather than being overwritten. The retained proposal binds the target’s immutable source and field generation, plus any supporting documents. A custom-field proposal also binds a one-way fingerprint of the prior typed display value; the value itself is shown through the ordinary authorized projection, not copied into hidden model history. A changed, cleared, or newly created prior value invalidates the proposal. Source, membership, document ACL, destination and reviewer authority are checked at resolution and again at the queued write. Creating new shared metadata also requires its current administrative authority. Hidden supporting documents are never exposed by review. Apply records a decision and queues the effect; it does not promise the field already changed. A later credential revocation, scope removal, source edit or authority change can block that effect. After authorization expiry, a newly requested identical inference can create a fresh review without reusing the old decision. Duplicate live proposals and repeated resolution requests do not create duplicate applications. Dismiss closes the suggestion without applying it. Unknown actions are read-only. Scoped API tokens may resolve these built-in suggestions, but the same source, field, ACL, destination, vocabulary and policy checks still gate the write. If the source or target changes before review, Suchi records a superseded transition, expires the task and cancels the run. Human metadata edits do this in their own transaction; startup and the existing approval sweep reconcile changes from other paths. The obsolete card leaves Approvals without requiring a dismissal. A later inference can create a fresh proposal bound to the current document. An effect already queued after an accepted decision still repeats all freshness and authorization checks before writing. This remains the extension pattern for 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 suggestions in the Dates tab; workflow approvals have a Decisions tab and dead jobs a Processing issues tab. Each date is added or rejected with its own buttons, and Add all N dates to Calendar above the dates accepts every addable date. Each action is one bounded API call over the affected IDs. 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. This review does not create approval definitions, runs, transitions, or one task row per date. See Document dates: Automatic and reviewed dates for automatic policy, legacy facts, review and rescan rules. Automatic acceptance never invents a reviewer; startup and settings saves never bulk-accept pending dates.

Rescan proposals

Suchi ships a rescan-proposal definition. A tagged release also carries independent OCR, content and LLM recommendation thresholds, defaulting to zero. When a positive recommendation 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 being processed, already shown under Processing issues, or waiting for a PDF password do not create a second rescan prompt. Operators can always select documents and run an explicit rescan. See Pipeline versions and rescans for tagged recommendation policy and dismissal behavior.

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.