Blog · August 12, 2026
The migration's own header comment said this was impossible: "it is IMPOSSIBLE to enable require_review_on_done without a default_reviewer_actor_id already configured." True — through one door. The completion gate never checked the other one.
Ledgenter lets a workspace set a floor: every task must clear review before it can go done, tenant-wide, no per-task opt-out required. Turning that floor on needs a reviewer to route to — a require-review flag with nobody behind it is a flag that blocks every completion in the tenant with no way to answer it. The RPC that sets the policy, completion_policy_set, enforces that pairing as an invariant: you cannot flip require_review_on_done to true while default_reviewer_actor_id is null, in either direction. Two pgTAP tests pin it. The header comment calls the resulting state "impossible."
One invariant, two doors
completion_policy_set is the front door, and it's airtight. But tenants.settings is an ordinary jsonb column, and Ledgenter's own design notes for this floor say so explicitly: a tenant "simply sets" the policy key. That's true of any Studio row edit too — a manual update tenants set settings = ... never touches the RPC, never runs its invariant check, and can land the exact combination the RPC was built to prevent: require_review_on_done: true with default_reviewer_actor_id absent.
The gate that actually enforces the floor, inside task_update's transition into done, didn't re-check. It read v_policy_default_reviewer and trusted it was non-null whenever v_policy_req_review was true — because the only supported way to reach that state made it so. Every other floor in that same function verifies its own precondition instead of trusting an upstream promise: the evidence floor checks for a real code ref or attachment at the moment of completion, the blocker check re-queries open dependencies live, the acceptance-criteria check reads the stored row. The review floor was the one exception, and the one place a single out-of-band write could reach it.
What breaks when the promise doesn't hold
If tenants.settings ever reached the "impossible" state through any channel other than the RPC, every ->done transition tenant-wide would hit the same branch and fail the same way: an error naming the default reviewer to route to — with nothing after the colon, because there was no reviewer. Not one task stuck; every task in the tenant, permanently, with no task_update call able to clear it, because the value the error message needed didn't exist. The exact "blocks completion tenant-wide with no way to unblock" failure the floor's own design was written to rule out — reachable by one edit the RPC layer was never in a position to see.
The fix doesn't change the supported path
task_update's elsif branch for the review floor now requires v_policy_default_reviewer is not null itself, not just v_policy_req_review. Reaching this branch through completion_policy_set is unaffected — its invariant still makes the bad combination impossible to write through that door, so the check is redundant on every path anyone can actually exercise today. It matters only for a policy that reached the invalid state some other way, and even then it doesn't silently re-enable the floor or paper over the misconfiguration: it fails open, the same posture the notify-delivery pipeline already takes when a routing decision is ambiguous. Floor not enforced beats every completion in the tenant permanently blocked.
A new pgTAP case sets the policy into the invalid state directly against the table — the one path that skips the RPC — and proves ->done still succeeds instead of raising an unroutable error. Body-only CREATE OR REPLACE, same signature, no contract drift, direct push.
Filed and fixed from a defect audit of the floor's own migration, not a support ticket or an incident — the gap was in a code path nothing had ever actually exercised, the same way most of the bugs on this blog are found: read the invariant a migration's comment claims, then check whether every caller that could reach the guarded state actually has to go through the door that enforces it.
Start at ledgenter.com.