Review the Posting Register
The Posting Register is a tenant-level console, outside any single project, where finance and accounting review ERP postings across every project and connection they’re permitted to see. Where ERP Post History is scoped to one project you already have access to, the Posting Register is the cross-project view built for a reviewer who needs to see postings from many projects and connections in one place.
The Posting Register is built for review first. Two bulk actions — clearing simulated postings and retrying failed ones — a single-row Retry on the detail drawer, Reversal, and reversing a whole intercompany run at once let you act directly from the grid and the detail drawer, AI Assist helps you find and understand postings faster, and Trends, Lineage, Control Totals, Closes, and Export let you analyze, drill back to source, seal a period, and get data out. Collaboration lets a team comment, sign off, and watch a posting together, without ever putting money in a notification.
Who Can Open It
Section titled “Who Can Open It”Opening the Posting Register takes one of four Keycloak realm scopes — erp.register.view, .operate, .approve, and .admin. They’re independent grants, not an escalating ladder: holding .admin does not by itself grant what .operate grants, and every mutating or egress action checks its own required scope, or scopes, explicitly rather than inferring them from a higher tier.
| Scope | Grants |
|---|---|
erp.register.view |
Open the register and review postings — the exception queue, grid, roll-up views, Trends, Lineage, and AI Assist. None of this applies, exports, or notifies anything. |
erp.register.operate |
The floor beneath everything that changes state or leaves the console: bulk actions, initiating a reversal, requesting approval for one, opening the approvals inbox and deciding a request you have authority over, seeing or handing back a delegation, exporting or scheduling a delivery, subscribing to the AI Assist digest, and posting a comment, sign-off, or watch. .approve- and .admin-gated actions are asserted on top of .operate, never in place of it — see below. |
erp.register.approve |
Approval authority over a reversal at or above the tenant’s segregation-of-duties threshold — either by holding this scope directly or through an active delegation from someone who does — and resolving a stuck reversal attempt (released or confirmed). Granting a delegation of that authority to someone else also requires holding .approve yourself; using, viewing, or revoking one doesn’t. All held alongside .operate. |
erp.register.admin |
The auditor export and as-of-read profile (unmasked money and maker identity) and setting the tenant’s retention policy — each held alongside .operate. Also lets you delete or fire another member’s schedule. |
The Visibility Rule
Section titled “The Visibility Rule”Holding an erp.register.* scope opens the console, but it doesn’t by itself make any posting visible. A posting is visible in the register only if you also hold a personal connection grant on that posting’s connection, and — when the posting belongs to a project — access to that project. A posting that isn’t tied to a project is gated by the connection grant alone.
This is a separate grant from the register scope above, and both are required:
- Connection grant. You need to be an explicit owner of the connection, or named individually, or a member of a security group named on it — the same grants a connection’s Security Model controls. A connection set to
All Workspace Membersdoes not grant register visibility. That setting makes the connection usable by everyone; it isn’t a personal, group, or ownership grant, and the register requires one of those specifically. - Project access, for any posting that belongs to a project — the same access your other project work requires.
A member who holds erp.register.view but no connection grants at all sees a correctly empty register, and the console tells them so rather than looking broken. A connection or project grant that’s revoked takes effect on your next page load — there’s no stale visibility to clear.
The Exception Queue
Section titled “The Exception Queue”Opening the register lands you on the Exception Queue, not the grid — the postings most likely to need your attention, grouped into four buckets and shown in priority order:
- In Doubt — the post was submitted and nothing yet confirms what became of it.
- Unconfirmed — submitted, and past the deadline it should have confirmed by.
- Pending — an asynchronous post, past the deadline it should have resolved by.
- Failed — rejected by the ERP.
“Aged” is measured against the platform’s own timers, not an invented threshold, so a posting lands in a bucket exactly when the platform itself would call it overdue. Within each bucket, the oldest postings come first.
Simulated postings never appear in the queue or its counts — the queue states how many were excluded, so a low count is never mistaken for “nothing to review” when simulations are the reason. Filtering to one bucket narrows the rows shown; it doesn’t change what the other buckets’ counts say, so switching to Failed never makes In Doubt look empty.
The same visibility rule as the grid applies here: you only see exceptions on postings tied to a connection you’re personally granted, in a project you can access.
Connection Health
Section titled “Connection Health”A banner above the Exception Queue and the roll-up views (below) answers a question neither of them does on its own: is one of your connections down? For every connection you’re personally granted — and only those — it shows the last successful post and whether that connection is currently erroring. A granted connection with no postings yet says so rather than being left off the list, and if the health check itself can’t be completed, the banner says that too rather than quietly reporting all clear.
The Register Grid
Section titled “The Register Grid”Switch to the grid to see every posting rather than only the exceptions — it lists postings across every project and connection you can see, one row per posting. Filter on:
- Project
- Environment
- Connection
- ERP type
- Entity
- Posting date
- State
Bulk Actions
Section titled “Bulk Actions”From the grid, select more than one posting and act on all of them together. Select postings by ticking their rows, or by choosing select all matching the current filter — which reaches every posting the filter matches across every page, not just the ones already loaded.
Two actions are offered:
- Clear simulated postings — a soft delete for simulated postings you no longer need to keep around.
- Retry failed postings — resend postings the ERP rejected, or that were never sent.
The Impact Preview
Section titled “The Impact Preview”Before either action runs, PlaidCloud shows an impact preview: how many postings are affected, the money involved (broken out by currency — amounts are never blended across currencies, and an uncaptured amount shows blank, never 0.00), and which connections and entities the affected postings belong to. Anything in your selection the action can’t touch is called out separately, so “24 of your 30 selected postings will do nothing” is visible before you commit, not discovered after.
Type-to-Confirm
Section titled “Type-to-Confirm”Above a threshold, Apply stays disabled until you type the affected amount to match it exactly.
Retry Only Runs Against What You Checked
Section titled “Retry Only Runs Against What You Checked”Clearing simulated postings can run against either kind of selection — ticked rows or everything matching your filter. Retrying as a bulk action can’t: it only ever runs against postings you’ve individually ticked. A filter-wide selection has no fixed list of postings to hold the retry to, so retrying asks you to paste the postings back in, and refuses to proceed unless what you paste is exactly what the preview showed — the same postings, no duplicates, and the same count. That binding is what keeps the confirmation honest: the batch you confirmed is the batch that gets sent.
What Can Be Retried
Section titled “What Can Be Retried”Only a posting the ERP rejected, or one that was never sent, can be retried. One still in flight, in doubt, or already posted can’t be retried from here.
Where the connection’s ERP supports it, PlaidCloud asks the ERP directly before retrying: if the ERP already holds the document as posted, the retry is refused and reversal is suggested instead. If the ERP can’t answer that check, the retry is refused rather than risked — it never guesses. A few connections don’t support this check at all; for those, the retry relies on the posting’s own recorded rejection.
Retrying requires erp.register.operate and your own personal grant on that posting’s connection — the same connection grant The Visibility Rule requires to see the posting at all.
Retrying From the Detail Drawer
Section titled “Retrying From the Detail Drawer”A posting’s detail drawer also carries its own Retry button, next to the watch controls — the same retry, one row at a time, reached without going through the grid at all. It’s not one-click: opening it shows the same impact preview and, above the threshold, the same type-to-confirm challenge the bulk action uses — there’s exactly one retry path, entered from two places. The button shows on every row for a member holding erp.register.operate; the drawer never pre-judges a row retryable before offering it, so a row that turns out to be ineligible — already posted, in flight, or one the ERP already holds — is refused by the preview with the server’s own reason, not silently hidden.
Clearing Simulated Postings
Section titled “Clearing Simulated Postings”Clearing is a soft delete: PlaidCloud records who cleared it and when, and requires a reason before Apply is enabled. It removes the postings from the simulate preview store and the ledger’s own simulate journal — it never touches a live posting, and there’s no way to point it at one.
The Simulated Postings View
Section titled “The Simulated Postings View”Simulated Postings is its own view, alongside the grid and the exception queue, listing what’s in the simulate store rather than making you find simulated rows in the main grid. Filter by connection, project, environment, or simulate run id.
- Include Cleared is off by default, matching the server’s own default: a cleared row is the audit record of a clear and is kept briefly for that reason, so the view opens on what’s still live in the store rather than its own history.
- Clearing from here still goes through the same impact preview as the bulk action on the grid — never a one-click clear — scoped to whatever the view’s filters currently match.
- The view’s summary line also reports the same
simulated_excludedfigure the Exception Queue shows — how many simulated postings in the posting ledger, a separate table from the simulate store, are held out of the queue because a simulated row never reached the ERP and so is never an exception.
AI Assist
Section titled “AI Assist”Assist opens a search box, a row of proactive cards, and a per-row advice panel — every figure on it is computed by the register itself, over your own live grants; the model, where one is configured, only explains or drafts, and never invents a number or a predicate.
Ask in Plain Words
Section titled “Ask in Plain Words”Type a sentence — “postings in doubt for the EMEA connection last week” — and it’s parsed into the register’s own filter vocabulary by a fixed table, not a model call: a parse can only ever narrow the rows the grid would already show you, never reach a row you weren’t granted. The model’s only role is to explain the parse in a sentence: it names the field it matched and how many of your rows the resulting filter finds.
Proactive Cards
Section titled “Proactive Cards”Seven cards summarize what’s worth a look, each with a live count and sample rows scoped to your own grants: outstanding to close, near-duplicates, the intercompany net-zero gap, changed vs. last close, confirmed in ERP, aging & owners, and already reversed. A short narrative sentence sits beside the figures where an LLM connection is configured for your workspace; where none is, the card still renders in full and says why the narrative is missing. An uncaptured amount on a card is always blank, never 0.00 — the same rule the roll-up views follow.
Per-Row Advice
Section titled “Per-Row Advice”Pick a posting and get two kinds of advice, depending on its state:
- A reversal draft, for any posting — what reversing it would look like: whether the connection’s driver supports it at all, the control-total it would need to tie to, and a period check. It is a draft only; nothing here reverses anything.
- Failure direction, for a rejected or in-doubt posting — why it failed, whether to retry it or fix the source data first, which field to fix, and the duplicate risk of pressing retry. The ERP’s own error message is free text, so it’s classified into a cause server-side rather than shown to you directly — the same rule that keeps free text out of the rest of the register.
The Daily Digest
Section titled “The Daily Digest”A digest previews, on demand, the cards above scoped to a close-relevant subset — outstanding-to-close, aging & owners, near-duplicates, the IC net-zero gap, and confirmed-in-ERP — as they’d appear if sent to you today. A toggle subscribes or unsubscribes you; the subscription stores nothing but your member id, so a grant you lose afterward simply drops those rows out of your next digest rather than leaking a stale view.
Reversal
Section titled “Reversal”Reversing a posting — creating a new, opposite document in the ERP — is available from the detail drawer’s Reverse control, and directly over the API for automation.
- Eligibility depends on the posting’s own state (only a posted entry with a confirmed ERP document id can be reversed), the connection’s driver (some, like Oracle Fusion, support no programmatic reversal at all), and whether a reversal attempt is already outstanding on it. The drawer re-checks eligibility both when you open Reverse and again immediately before you submit, so a row that’s gone stale in between — another reversal already outstanding, say — shows the driver’s own refusal in its own words rather than firing a doomed request.
- Reversing requires
erp.register.operateand is bound behind a type-to-confirm challenge: you retype the posting’s own ERP document id, checked only in the browser and never sent, before Reverse unlocks — the same blast-radius pattern bulk actions use, a safety prompt rather than an approval step. - Reversing can optionally redirect the new entry to a different target period than the original posting — honored on adapters whose ERP accepts an explicit posting period, refused with a clear error on ones that can’t aim it. A redirect can still land in a different period than requested: some adapters only learn whether they honored it after dispatch, so the drawer states a landing period only once the attempt has actually settled as reversed — never earlier — and defers to the server’s own message for every other outcome. A hard database latch stops a second reversal attempt from ever being dispatched while one is outstanding, even across a process crash mid-dispatch; an ERP rejection releases that latch automatically, since nothing was created.
- A reversal left
pendingorin_doubt— its outcome unknown — doesn’t resolve itself; v1 has no automated reverse-confirmation, by design. The drawer’s resolve controls clear it, gated onerp.register.approvein addition to.operate: a human checks the ERP directly and records what they found — Release (nothing was created there, so the ledger is untouched and the posting becomes reversible again) or Mark Reversed (a reversing document exists, with its id) — which is the only way that latch is ever cleared. Marking a reversalconfirmedis permanent; there’s no undo through the product.
Segregation of Duties
Section titled “Segregation of Duties”A reversal at or above your tenant’s configured threshold requires approval before it proceeds — and approval is something an approver does, not a name the submitter supplies on the request.
- Maker≠checker. The member submitting the reversal can’t also be its approver, and can’t be their own break-glass authorizer.
- Measured by magnitude. The threshold compares the size of the reversal regardless of sign — reversing a credit is measured the same as reversing a debit.
- Recent reversals count toward the threshold. A rolling window totals a submitter’s own reversals on the same connection, so a large reversal can’t be split into several smaller ones to stay under it. Amounts are summed by magnitude, not netted — a negative reversal and a positive one don’t cancel each other out.
- Fails closed. If a prior reversal in the window can’t be verified — an uncaptured amount or currency, for instance — the reversal requires approval rather than skipping the check.
- The approver must be qualified. They need
erp.register.approve— or an active delegation from someone who holds it — and their own grant on the connection being reversed. If fewer than two members hold both, reversals at or above the threshold are refused rather than let through. - Break-glass remains the one path where the submitter names who authorized an override directly: a genuine emergency, decided by an authorizer independent of the operational chain — holding
erp.register.adminbut not.operateor.approve, plus their own grant on the connection — and every override is permanently recorded to the audit trail. - A refusal doesn’t say why. Whether a request has no qualified approver, was decided by the wrong person, or was never opened, the reversal is refused with the same message — deliberately, so a refusal can’t be used to map out who holds which role or grant. The actual reason is in the audit trail, not the error.
- A run reversal needs one approval per leg, not one for the run. Reversing a whole intercompany run at once doesn’t get a single run-level approval — every leg needs its own, because an approval is bound to one posting, one connection, and one approver holding a grant there, and there’s no single name to bind a whole run’s worth of legs to.
- Scope. This gate covers reversals initiated from the Posting Register. Reversals and posts issued through the project-level ERP posting API aren’t covered by it yet.
Turning segregation of duties on, and setting its threshold, is configured for your tenant by PlaidCloud — there’s no console toggle for it yet.
The Approvals Inbox
Section titled “The Approvals Inbox”When the threshold requires one, Request Approval — offered alongside Reverse in the detail drawer — routes the reversal to every approver who holds a live personal grant on that connection. There’s no one to address it to; the connection grant is the routing. Approvers work the queue from Approvals on the console toolbar: an inbox of requests waiting on their decision, and a second queue showing the requests they’ve submitted themselves. Each row carries the posting’s amount, entity, and period, and how long it’s been waiting, so deciding never means leaving the queue to go look something up first. Approve or Reject takes one reason, recorded with the decision.
An approval is bound to exactly what it was granted for — the posting, its connection, the stated reason, and the target period — and can’t be reused for a different reversal, a different reason, or a changed target period; a changed request needs a fresh approval. Only one request can be open on a posting at a time, and an approval is spent the moment it’s redeemed. A brief hold follows every approval, during which either the approver or the submitter can still cancel it — once the hold passes, the reversal may already be a document in the ERP, and nothing undoes that. Everything is re-checked again at the moment the reversal is actually applied — the approver’s role, both parties’ access to the connection, and the tenant’s two-approver minimum — so an approval granted earlier doesn’t survive the approver losing access in the meantime.
Delegation
Section titled “Delegation”An approver can delegate their approval authority to another member for a bounded window, from the Delegations window on the console toolbar — useful when an approver is going to be unavailable and reversals still need deciding. Granting a delegation needs erp.register.approve; using one, seeing your own, and handing one back only need .operate, since the typical delegate doesn’t hold the approver role at all — that’s the point of delegating to them.
Self-delegation is refused, and so is a reciprocal pair (delegating to someone who has already delegated to you) or any longer chain — none of these are honored, so two members can’t quietly make each other’s decisions count as covering both of them, directly or through a middle step. Maker≠checker still applies through a delegation: a delegate can’t approve a request from the person who delegated to them, and can’t approve a request of their own either way. Every decision a delegate makes is recorded in the audit trail as made under the delegating approver’s authority, not as if the delegate held the role outright.
Escalation
Section titled “Escalation”An approval sitting too long without a decision raises an alert, so it doesn’t just age silently in a queue nobody’s watching. Each recipient is told only about the requests they themselves could actually decide — a colleague’s escalation email never names a request routed to somebody else’s grants — and the alert carries no amount and no free text, the same minimization the rest of the register’s notifications follow.
Intercompany Runs
Section titled “Intercompany Runs”An intercompany run is the group of postings — its legs — made together for one close, identified by the close day and sequence stamped onto them at the time, never by the workflow run that produced them. (That workflow run id lives on separately in the ledger’s own history and can outlast a posting’s close stamp, so it isn’t a safe way to identify a run.) List runs, open one to see its legs tied out and paired, and reverse the whole run as a single governed action.
Reachable through the API only for now — GET /erp/register/runs, GET /erp/register/runs/{run_day}/{sequence}, and POST /erp/register/runs/{run_day}/{sequence}/reverse — there’s no console screen yet.
Net-Zero and Pairing
Section titled “Net-Zero and Pairing”Open a run and its legs are tied out two ways, both scoped to the connections you’re personally granted — the same visibility rule as everywhere else in the register, so a run spanning connections you only partly see is reported as partly visible rather than as unbalanced.
- Net-zero, per currency: a balanced, imbalanced, or indeterminate verdict, with the entities behind each net broken out. A currency isn’t tied unless every leg in it was captured — one uncaptured leg makes the whole currency indeterminate, never a net computed over only what happened to be measured.
- Pairing matches each payable leg to its receivable counterpart by a pairing key the posting workflow stamps into both before either is submitted. A matched pair nets to zero in one currency; everything else carries a named reason — no counterparty leg visible to you, an uncaptured amount, a net that genuinely isn’t zero, or cross-currency, which is reported and never tied, since there’s no foreign-exchange rate anywhere in the platform.
A run larger than 200 legs is too large to tie out or pair in one response: both come back indeterminate rather than computed over a truncated slice of the run, so a large run never reports a false balance, or a false missing counterparty, caused only by its own size.
Reversing a Run
Section titled “Reversing a Run”Reverse every leg of a run in one action, from POST /erp/register/runs/{run_day}/{sequence}/reverse.
- Eligibility is checked for every leg up front. Anything knowable in advance — state, adapter support, an outstanding attempt, your own connection grant — refuses the whole run before a single request reaches an ERP.
- What can’t be known up front is reported afterward, per leg. Live ERP and authorization state can change mid-run, so a run can finish partially reversed even though nothing looked wrong at preflight. Nothing is auto-compensated — posting more documents to unwind a partial failure is a riskier write than the one that failed. A partial run is remediated leg by leg, the same way a single reversal is.
- Re-running a run reversal is how a partial one gets finished. Legs an earlier attempt already reversed are set aside rather than refused, so trying again only reverses whatever’s actually still left.
- Segregation of duties applies per leg, not to the run’s total. When your tenant’s SoD policy is enforced, every leg needs its own approval before the run dispatches anything — at any amount, not only above the threshold. This is deliberately conservative: a leg’s own requirement can only be settled the moment it’s dispatched — a rolling anti-structuring window that counts the run’s own legs as they reverse, and a live ERP read-back that can fail — so demanding every approval up front is what stops a run from reversing half its legs before discovering partway through that the rest need approval too.
- Bulk actions cover the whole run in one call.
POST /erp/register/runs/{run_day}/{sequence}/approval-requestsopens an approval request for every leg the submitter can act on, andPOST .../approval-decisionsdecides every leg an approver is qualified for — one call apiece instead of a request and a decision per leg (20 calls for a routine 10-leg run). The security model underneath is unchanged: each leg still gets its own approval, bound to that posting, its connection, the reason, and the target period, and the approver still needs their own access to each leg’s connection — a leg they can’t authorize simply stays pending for someone who can, never swept in. A caller with no approval authority at all is refused outright, without learning which legs have requests open. Results come back per leg, so a partially-authorizable run reports exactly which legs were decided and which stayed pending, and why. - Break-glass isn’t available for a run reversal. It’s a two-person override of one posting, and applying one witness’s authorization across a whole run would multiply it by the run’s leg count. Take break-glass per leg from
POST /entries/{ledger_id}/reverseinstead. - Runs above 200 legs can’t be reversed as one action. Reverse them in parts from the entry list instead.
Trends
Section titled “Trends”Trends shows failure rate and latency, grouped by connection or ERP type, plus the reversal reason-code distribution — every figure, including every denominator, computed over your own live grants. A connection with nothing terminal in the window shows an em dash for its failure rate, never 0%, since a perfect zero would put a connection nobody uses at the top of a health list. Latency is a bounded sample over the most recent terminal postings, labeled as a sample rather than presented as if it covered the whole window. Reversal reasons appear as their structured codes only — the free-text reason a person typed is never bucketed or shown here.
Lineage
Section titled “Lineage”Lineage drills from one posting back to the workflow run that produced it, and out to the document in the ERP itself. Look it up by run id or by a posting’s ledger id — asking by ledger id resolves the run through your own grants first, so a posting on a connection you can’t see resolves nothing rather than exposing which run it came from. Where PlaidCloud can verify the ERP’s document URL shape for that adapter, lineage includes a deep link straight to the document; where it can’t, or the posting was never confirmed, it says which of those is why rather than guessing at a link. The ERP’s business key still never appears here — the lineage key is the workflow’s run_id, and the ERP pointer is confirmation_id, the same as everywhere else in the register.
Closes
Section titled “Closes”Request a close to seal a period — for one or more connections and entities — into an immutable, point-in-time snapshot: everything the register knew about those postings as of that moment, kept even if the live rows are later retried, reversed, or cleared. It’s aimed at a locked accounting period where you need a defensible, unchanging record rather than whatever the live grid shows today. Requesting or reading a close is reachable through the API only for now; there’s no console screen yet to request or browse one.
Requesting a close (erp.register.operate) is a tenant-wide administrative action, not a personal one — the connections and entities you name are exactly the ones sealed, regardless of your own connection grants. Re-closing an already-closed period is never destructive: it always produces a new, separately numbered revision rather than overwriting the last one.
Once a close is materialized, reading it back applies the register’s usual rules, re-resolved live on every read rather than baked into the snapshot at seal time: you only see rows on connections and projects you’re currently granted. Unlike the live grid, which shows money and maker identity to any viewer who can see the row at all, a close’s figures are masked unless you hold erp.register.admin — the same rule Export applies. A close also reports its own late-arrival count: postings submitted or changed after the close’s high-water mark, and so never captured in the seal — visible only by requesting a new close for the same period, since nothing re-opens an old one.
Export
Section titled “Export”Exports & Alerts is where the register leaves the console as a file or a notification — and the one surface where PlaidCloud’s controls stop applying the moment the bytes leave. Producing an export or scheduling a delivery requires erp.register.operate; opening the register to look at it does not.
Downloading Now
Section titled “Downloading Now”Export the register you’re currently looking at as an Excel-friendly CSV or as JSON, built fresh under your own live grants. Two masking profiles apply depending on your role:
erp.register.operategets the standard, masked profile: money and maker identity are withheld.erp.register.admingets the auditor profile — the only one that carries money and maker identity unmasked.
Every export follows the same rules as the rest of the register: natural_key never appears, free-text fields (comments, dimension and worktag values) are excluded outright rather than merely scrubbed, and an uncaptured amount is blank — distinguished from a masked one, so a blank never reads as “nothing was posted” when it actually means “your role doesn’t see this.”
Scheduling a Delivery
Section titled “Scheduling a Delivery”Create a schedule — a filter, a cadence, a format, and a list of recipients by member, or a Slack connection for a notification with no row content at all. Two kinds are offered:
- Export — a recurring CSV or JSON delivery of the filtered register.
- Alert — a notification triggered by one of three conditions: a failed live post, an aging authorization, or a posting reversal. Preview what a trigger would currently match for you before subscribing to it.
Each recipient’s file is built from their own live grants at the moment of sending, not the schedule owner’s — two recipients on the same schedule can receive two different files, and a recipient who has since lost the export role, lost every connection grant, been disabled, or has no address on file is skipped individually with a stated reason rather than silently dropped. Only the schedule’s owner or an erp.register.admin can delete or fire someone else’s schedule.
Retention
Section titled “Retention”Configure how long the register keeps three kinds of history: captured payload detail, simulated postings, and the audit trail — each as a day count, tenant-wide, requiring erp.register.admin. Every field is written on every call; an omitted field clears that horizon rather than leaving it unchanged, and an unconfigured tenant keeps everything (every horizon reads as null, not a hidden default).
The retention sweep that acts on this policy now runs automatically, once a day, tenant-wide — the same periodic-jobs mechanism that also drives scheduled exports and alerts, ages overdue postings into the exception queue, and expires old simulated postings.
Roll-Up Views
Section titled “Roll-Up Views”Group the register by run, period, or connection to see subtotals and a status roll-up instead of individual rows, reachable from the register alongside the grid and the exception queue.
- Blank money stays blank. A posting with no captured amount — every SAP posting, a born-terminal posting, or one written before this feature existed — contributes nothing to a subtotal and is never shown as
0.00. Each group states in words whether every posting in it was captured, some weren’t, or none were. - Currencies are never mixed into one total. PlaidCloud does no foreign-exchange conversion, so a group spanning more than one currency is broken out by currency rather than blended into a single misleading figure.
- A capped group list still totals correctly. If a grouping produces more groups than the view displays, the totals line still covers every group, not just the ones shown, and says so.
The Connection Health banner appears on this view too.
Control Totals
Section titled “Control Totals”Control Totals is its own view, reachable alongside Trends and Lineage, over the same connections and entities The Visibility Rule already scopes you to. It groups postings into batches and states, for each one, a tri-state verdict — Balanced, Imbalanced, or Indeterminate — with the server’s own stated reason, never a bare word.
- Indeterminate is a real answer, not a soft pass. A batch is Balanced only when every row in it was measured and its groups tie. An empty window, an uncaptured amount, an adapter that fires and forgets, or a scan cut short before the whole batch was read all come back Indeterminate, with the reason spelled out — never a default green.
- Money is blank, never zero. A group’s source and posted totals, and its diff, are blank whenever the amount wasn’t captured or confirmed — the same rule the roll-up views follow, because a fabricated
0.00would understate an unmeasured batch while reading as an authoritative figure. - Groups are per currency and entity, and never summed together. PlaidCloud does no foreign-exchange conversion, so a batch spanning more than one currency or entity lists each group’s own totals side by side rather than blending them.
- Rows that predate capture get their own
(no batch id)bucket. A posting written before batch capture existed can’t be regrouped into a batch that never held it, so it’s shown as its own row rather than folded in or dropped.
The same read also covers two related questions: period-close readiness, per entity and period, which degrades to Indeterminate — not a false Blocked — for a bucket the platform has no numbers for yet, such as a pre-capture row at a cutover close; and confirmation drift, reported per document rather than per group, because two documents drifting in opposite directions inside the same currency/entity group can tie out at the total and hide both.
The Detail Drawer
Section titled “The Detail Drawer”Click a row to open its detail drawer. It’s organized into tabs:
| Tab | Shows |
|---|---|
| Request/Response | The outbound request and the ERP’s response, filtered for data minimization (see below). |
| Errors | Any error the ERP or the posting step returned. |
| Timeline | The posting’s states in order, from submission to its current state. |
| Related | The original posting and its reversal, linked to each other, when one exists. |
| Audit | A read-only record of activity on this posting. Sparse for now — see The Audit Tab below. |
| Comments | Threaded comments on this posting, with @mention by member id. See Collaboration. |
| Sign-off | The posting’s current review status — Reviewed, Cleared, or Needs Follow-up — with its full history. See Collaboration. |
Collaboration
Section titled “Collaboration”Work a posting with your team without leaving the register: comment on it with @mention, record a sign-off, or watch a connection or a run for its future activity.
- Comments are threaded, plain-text notes on one posting, from its Comments tab. @mention a colleague by member id and they’re notified — if they can currently see the posting; that check is redone at send time, never assumed from who was mentioned.
- Sign-off records one of three states — Reviewed, Cleared, or Needs Follow-up — with an optional note, and keeps the full history of who set what, when. It’s a record, not a gate: nothing currently blocks a posting or a reversal on its sign-off state.
- Watch a connection or a run — two separate toggles — to be notified of activity on either one going forward.
Posting a comment, a sign-off, or a watch requires erp.register.view and .operate; reading them back requires .view alone.
Data Minimization
Section titled “Data Minimization”The register is built to show what a reviewer needs to confirm a posting happened, without surfacing the sensitive data a posting step handled to make it happen.
- Request and response payloads are allow-listed per adapter. A field only appears if it’s been explicitly classified as safe to keep. Bank account numbers, routing numbers, IBANs, tax ids, and other personal identifiers are stripped before you ever see the payload.
- The ERP business key is withheld entirely. It can embed a vendor name or another reference token, so it never reaches the register — including AI Assist: the same allow-list that decides what you see decides what a model prompt is allowed to see, and a natural-key value anywhere in that payload is refused outright rather than sent. Identify a row by its ledger id, and use the
confirmation_idas the ERP’s own pointer to the document — the same field ERP Post History callsconfirmation_id. - Free-text fields are pattern-scrubbed on read, and excluded outright — not just scrubbed — from the digest, any AI model prompt, and any export. Pattern-scrubbing catches a shape like an IBAN or a tax id; it can’t catch a vendor name typed into a memo, which is why anything leaving the console as a file drops those fields entirely rather than relying on the scrub alone.
The Audit Tab
Section titled “The Audit Tab”The Audit tab is display-only. Its detail is intentionally sparse in this release, because the underlying audit vocabulary hasn’t been classified yet — expect it to fill in as that work lands, not to change how you read the rest of the drawer.
Everything else on this page — the exception queue, connection health, roll-up views, bulk actions, single-row retry, reversal, control totals, AI Assist, trends, lineage, closes, collaboration, and export — works today.