Skip to main content
Gating actions on exceptions stops a reviewer approving data that is broken. The Form Completeness Gate stops a reviewer approving data they have not looked at — a half-read form where two tabs were never opened and the instruction panel was never expanded. The gate is a per-form checklist of “you must do X before you can finish” requirements. It is fully opt-in: existing forms and actions are unchanged until you add the props described below.

The problem

A review form has three tabs — line items, charges, and a panel of reviewer instructions tucked at the bottom. A reviewer who only ever looks at the first tab can still click Approve: the document had no open exceptions, the button was enabled, and the task transitions to approved. Nobody actually read the charges, and the instruction panel that explained how to handle a multi-stop shipment route was never even expanded. The gate closes that hole. The reviewer cannot finish until they have visited the data you flagged as mandatory.

The pattern

A single action property turns the gate on: It lives under metadata.actions[].properties in the task template YAML, alongside the existing exception gates. The gate is evaluated entirely in the UI whenever a requirement is satisfied — there is no round trip to the server. When the gate blocks an action, an amber info icon appears next to the button. Clicking (or keyboard-focusing) it opens a popover headed Before continuing: that lists the outstanding items as bullets. It shows up to six items; if more remain it appends a …and N more line.
gatedByCompleteness combines with the exception gates from Gating actions on exceptions. All the disable rules are OR-ed together — any one of them is enough to keep the button disabled.

What counts as outstanding

The gate collects requirements from two places: the layout components on the form, and the open data exceptions on the paths the form binds.

Opting fields in

The mandatory requirements come from props on the layout components themselves, not from the task template. Add them where the field is rendered in the data form schema. See Layout Components for the full prop tables — the gate-specific props are:
mustExpand only has an effect on a collapsible panel. Set collapsible: true on the same v2:panel or the requirement is dropped and a warning is logged in dev.

Exception scoping

The non-exception requirements (mustView, mustExpand, mustScroll) always apply to a gatedByCompleteness action. Exception-source requirements are scoped:
  • If the action also declares onlyEnabledIfNoOpenExceptionsForPaths, only exceptions on those listed paths fold into the gate. (See Gating actions on exceptions.)
  • Otherwise, every open exception on a path the form binds applies.
A form’s bound paths are the tagPath / groupTaxon values of every component it renders. Exceptions on paths the form does not render never fold into its gate, and matching is hierarchical — an exception on a child attribute is in scope for a panel bound at its parent group. An exception blocks the gate while it is open and has no closing comment; resolving it (or adding a closing comment) clears it from the gate.

Example

An invoice review form with two tabs after the first, a collapsible instruction panel the reviewer must open, and an Approve action gated on completeness:
Until the reviewer opens the Line Items and Charges tabs, expands Reviewer Instructions, and clears any open exception on a bound path, Approve stays disabled and the popover lists what is left: Review Line Items tab, Review Charges tab, Expand Reviewer Instructions, and one bullet per outstanding exception.
The gate is in-memory and lives for one form view. Reloading the form starts the reviewer over — every tab, panel, and scroll requirement is outstanding again. Keep the list short enough that a re-read is not punishing.

Recipe summary

  1. On each layout component, opt the mandatory fields in: mustView on a v2:tabs, mustExpand (with collapsible: true) and/or mustScroll on a v2:panel.
  2. On the action in the task template, set gatedByCompleteness: true.
  3. To restrict which exceptions count, add onlyEnabledIfNoOpenExceptionsForPaths to the same action.
  4. Keep a reject or escape action ungated so a reviewer is never trapped.
  5. Test by leaving one flagged tab unopened — the action must stay disabled and the popover must name it.

Next: requiring comments

The completeness gate makes sure a reviewer has seen the data. The next recipe — Requiring comments on actions — makes sure they explain a decision before it is recorded.