The seal: approval status that can't be faked
Most approval workflows end by writing a status cell that anyone can edit afterwards — the ceremony is elaborate and the record of it is a suggestion. Here is what it takes to make "Approved" mean something: a status only the flow can write, gates that watch the linked records, and a sealed state the whole product respects.
Every work tool will sell you an approval workflow. Forms, routing, notifications, sometimes a diagram with swim lanes. And in almost every one of them, the entire ceremony ends the same way: by writing the word Approved into a status column.
Which is an ordinary column. Editable by anyone with edit rights, the same as Notes.
Sit with that for a second, because it undoes the whole feature. Whatever ritual produced that value — two managers, a legal review, a deadline sweated over — a hand-edit produces the identical value in half a second, and no reader can tell the difference afterwards. The workflow is theatre. The cell is the record, and the cell is a suggestion.
There's a second hole, quieter and worse. Suppose nobody fakes the status. The record got approved properly — and then someone edits it. The amount changes on Tuesday, a line item is added on Thursday. The status still says Approved. Approved what, exactly? Not this. The thing that was approved no longer exists; the word just stayed behind.
Any approval system that doesn't answer both problems is a notification system with better marketing. So we built ours to answer both.
A status only the flow can write
In RowFold, a table's posting rules write every step of the journey through a real Select field — Draft, Awaiting Finance, Changes requested, Approved, Posted. Deliberately a real field: it means "everything sitting with Finance" is a saved view, a board column, a report group and an automation trigger with zero extra machinery, because approval state is an ordinary value rather than a parallel universe bolted on beside your data.
But an ordinary value with one exception: by default, only the flow can write it. Hand edits are refused. Bulk edits are refused. Imports skip it and say so. An automation step that tries fails with a named reason in its own run log, and the API gets a clean refusal with a stable error code. An Approved in that column always traces back to a real decision by a real person — which is the entire reason to trust the column.
The stages behind it are the part you'd expect, done properly: ordered stages, each naming its approvers as picked people, a role, or — the one fixed lists can't do — a People field on the record itself, so the account manager approves their own account's records, per record, automatically. Each stage sets its quorum: everyone, any one, or N of M. A met quorum advances the record that instant, in the same transaction. A stage can carry conditions, so the CFO stage exists only when the amount says it should. And a rejection always carries a reason, because a bare no is the least useful sentence in business.
Gates: the linked records hold the door
Here is where being a relational workspace stops being an architecture diagram and starts being a policy you can enforce.
An invoice is never just an invoice. It's a parent of line items, a child of a purchase order, a sibling of a delivery. In a spreadsheet-shaped tool, each of those lives in its own table with its own status column, and nothing — nothing — can make one table's approval wait on another's. The relationships exist in your head and in a lookup formula, not in the rules.
A RowFold posting policy can carry gates: conditions over the records on the other end of a relation that must hold before the seal goes on. Every linked line item is Approved. The linked PO is itself Posted. The gate travels the same relationship routes that lookups and rollups do, its verdict sits on the record's panel while people wait, and it re-checks at the moment of posting so nothing slips through on a stale reading.
One detail we're particular about: "every linked line item is approved" is vacuously true of an invoice with no line items — and vacuously posting an empty invoice is almost never what anyone meant. So an empty relation blocks the gate unless the policy explicitly says empty is fine. Logic that's technically correct and practically wrong is still wrong.
Posted is a seal, not a synonym
The journey ends at Posted, and Posted is the answer to the second hole. The record is stamped — when, and by whom — and from that moment every write path refuses it. The grid. The record page. The drawer. Bulk edits. Imports. Automation steps. The API. There is no door around the side, because the refusal lives at the one choke point every write in the product already passes through.
What was approved is now what exists. A posted invoice is the invoice that was sent, indefinitely, because nobody can "just fix" a number on it three weeks later.
The seal locks content, not usefulness. Attachments and generated documents can still be added — the signed PDF of a posted invoice is a note pinned to the seal, not the sealed content. Other records still link to it; the conversation stays open; reports read it happily. But deleting a posted record is refused outright — unpost first — and unposting is the deliberate, audited escape hatch: delete-level access, a written reason, both on the record for good. A policy can also seal children with their parent — post the invoice and its line items lock with it, carrying the identical stamp — and a date field unlocks a period lock: post everything dated on or before a chosen day, in one action, the way an accounting system closes a month.
The deciders are people, on purpose
Approvals fail in practice at the human step, so the human step got the most attention. Asks land in one queue across every workspace, with the keyboard doing the work. Routine yeses happen right in the notification. And approval emails carry decide buttons that open a signed confirmation page — no login, because being asked is the authorization, and the links expire in two weeks.
The detail that matters: opening that link never decides anything. Corporate security scanners follow every URL in every email they deliver, and there is a well-known work-management tool whose most famous support complaint is the security appliance auto-declining approvals on arrival. The confirmation page's explicit press decides; a robot following links decides nothing.
The same principle holds at the edges. Escalation can auto-approve or auto-reject an overdue ask, but an auto-outcome always writes a note saying that's what it was — no silent robot decisions in a trail people rely on. And the public API can read trails, raise asks, even post and unpost records, but there is deliberately no machine decide endpoint. "Who approved this" must always have a person's name for an answer.
That's the whole design, really. Approval state you cannot fake, gates that make it relational, a seal the entire product respects, and decisions that are always human. The word Posted starts to mean something in a team — and a word that means something is the point.
We keep a running comparison of how this stacks up against the tools you're probably evaluating on the compare page, structural claims only.