August 2026
-
New users get a guided first run instead of an empty workspace. A brand-new workspace no longer opens on blank grids — on every plan. Every empty screen — Projects, Workflows, Tables, Connections, Dashboards — now explains what belongs there and offers the action to create it, so there’s always an obvious next step; a viewer with no edit access sees the explanation without actions they can’t take. A new workspace also offers Load sample: one click seeds a ready-made Retail Sales Analysis project, runs its workflow, and opens the result — so you reach a real first result in a few minutes without building anything, with every piece it made yours to open and change. If loading or running the sample runs into trouble, PlaidCloud says so and lets you try again. Already know your way around? Dismiss the guidance — a quick confirmation reminds you it’s still there — and bring it back any time from the user menu in the upper right with Restart Onboarding. See Start With the Sample Project.
-
External lakehouses are fully operational — keep a project’s data in your own Snowflake or Databricks, with native file import and dashboards. A new project can use your own Snowflake or Databricks lakehouse as its data backend instead of the built-in PlaidCloud Lakehouse. Its workflows read and write tables directly in your warehouse, so the data stays in your account under your governance and billing while PlaidCloud drives the transformations, workflows, and dashboards over it. A PlaidCloud administrator registers the lakehouse for your tenant — Snowflake with a superuser, database, warehouse, role, and a key pair; Databricks with a SQL warehouse HTTP path, its Unity Catalog catalog, and a personal access token — after which it appears in the lakehouse picker when you create a project. Importing a CSV, Parquet, XML, or Access file into a lakehouse-bound project now loads through the warehouse’s own native, parallel bulk-load path — a Snowflake internal stage or a Databricks managed volume, each with
COPY INTO— rather than staging through an external cloud bucket, so it works the same way on whichever cloud your warehouse runs. Dashboards work over both engines: Databricks through its driver, and Snowflake with key-pair auth, enabled per tenant, appearing automatically on new projects and on an existing project’s next publish. See Use an External Lakehouse. -
Pull NetSuite financials with ready-made import steps — no query to write. Three canned steps read the data most NetSuite pulls start with: Import Balances for a trial balance, Import GL Detail for the transaction-line detail behind it, and Import Master Data for reference lists like accounts, subsidiaries, departments, and vendors. Pick a NetSuite connection, name a target table, set a date range and (optionally) a subsidiary, and run — PlaidCloud signs in with OAuth 2.0, pages through large results, and retries transient errors, so a full-period or all-subsidiary pull comes back complete. For a bespoke pull the canned steps don’t cover, the connector still runs your own SuiteQL through the REST Request step, handling the token exchange, the paging, and turning NetSuite’s all-text values into typed columns. See Import NetSuite Financials, Connect to NetSuite, and the NetSuite REST Connector reference. Companion guides cover Sage Intacct, and QuickBooks records its prerequisites while that connector is in progress.
-
See at a glance whether a connection points at production or a sandbox, and test a database connection before you use it. Every connection editor now has a Sandbox (non-production) connection toggle with a live badge — green SANDBOX or red PRODUCTION — so you can label a staging or sandbox connection and tell the two apart before running a step against it. Database connections (Databricks, Snowflake, PostgreSQL, and Redshift) also gain a Test Connection button that checks the credentials and reports success with the server version, or the reason it failed, without closing the editor. See Create and Manage a Connection.
-
Pull Sage Intacct statistical accounts (headcount, square footage, units) directly from the Import Sage step. A new Statistical control returns financial account balances, statistical account balances, or both, in the same trial-balance shape as before — so a per-head or per-unit metric no longer needs a separate export or a custom query. See Import Sage and Analyze Sage Intacct Financials.
-
Review every ERP post your project has made, and its live state. A new read-only ERP Post History surface shows each journal entry or document posted (or attempted) to an ERP — Sage Intacct, NetSuite, SAP — with the ERP’s own document number, timestamps, and its current lifecycle state: preflighted, submitted, pending, posted, rejected, in doubt, or reversed. Scope it to a project you can access and optionally narrow by connection or state — for example, list only the posts still in doubt that need checking in the ERP by hand. It reads the same durable ledger that stops a document being posted twice, so it is the standing record across every run and workflow, not just one run’s result table, and it is strictly read-only. Available over the REST API (
GET /analyze/erp/write/history) and as theerp_post_historyMCP tool, paged newest-first. See Review ERP Post History. -
Post journal entries to Sage Intacct from a workflow — no code required. The “Intacct: Post Journal Entry” step writes journal entries back to Sage Intacct over its REST API. Map a header table (one row per entry) and a lines table onto the journal-entry fields, correlate the two with a shared Entry Key column, and the step batches many entries in one run, posts each, and records every entry’s outcome — posted, failed, or an inconclusive result to check — in a result table you choose. Run it with Preview on first to validate every entry and see exactly what would post without authenticating or touching your GL, then re-run with Preview off to post for real. It replaces writing a posting user-defined function by hand. See Intacct: Post Journal Entry.
-
PlaidCloud now hosts Plotly Dash apps, at parity with server-side Panel apps. Publish a Dash app from a Git repository the same way you publish a server Panel app: PlaidCloud builds your code into a container, serves your own app at its published URL, idles at zero replicas, wakes on the next request, and rebuilds automatically on every push to the connected branch — whether your entry point sits at the repository root or in a subfolder. Each viewer signs in with the platform’s single sign-on — with no authentication code in your app — and every read your app makes runs as that viewer, the same per-user, row-level-secured data access a server Panel app gets, through a small Dash helper you call inside your callbacks. My Panel Apps lists Dash apps alongside your Panel apps, with build status, logs, locking, and rebuild all working the same way. See Deploy a Dash App From PlaidCloud Git.
-
Execution containers — run a block of related steps as one sealed unit. On the Advanced workflow canvas, right-click a group and toggle Execution on: the group becomes a self-contained sub-workflow with its own entry and exit ports and behaves as a single node in the parent. Nothing inside starts until the group’s inputs arrive and nothing downstream starts until every member finishes, while independent branches inside still run in parallel; disabling a container skips it — and everything downstream of it — as a unit.
Run and monitor it as a unit. Run Group and Run Group + Downstream rerun the container in place without rebuilding its upstream, the container carries a rolled-up status — a dot, an N of M done count, and a colored border — and Retry from Failure re-runs only the failed members and what depends on them. The Run Monitor shows each step’s container and its rolled-up status alongside the canvas.
Gate it, or iterate it, from Container Settings… Right-click and choose Container Settings… for two tabs. Conditions offers the same variable, table, document, and time checks a step’s Conditions tab does, deciding whether the container runs at all: they are checked once, when the container is reached — not per member and not per iteration — and a container that fails them is skipped as a unit, taking everything downstream with it. Unlike a step, a container has no “go to step” on a failed condition; a failed condition always means skip and move on, and a genuine error while evaluating one fails the run rather than silently skipping. A disabled container is skipped regardless of its conditions, and resuming a run that skipped a container this way leaves it skipped rather than re-checking. Tick Iterate this execution container to run the whole sealed group once per value in a set instead, using the same loop-variable model as the Workflow Loop step — an explicit list or range, or the unique combinations of columns in a table — so a member’s filter, expression, or output name changes each pass, up to 1,000 iterations. See Execution Containers and Container Conditions.
-
A conditional step now shows it on the canvas, and its conditions are one click away. A step’s run conditions were only visible by opening the step, so tracing a flow on the Advanced workflow canvas gave no indication which hop was gated. The connector leading into a conditional step is now dashed and carries a small shield at its arrowhead — the dash being what you read once you are zoomed out far enough that the shield is too small to pick out. Click the shield, or right-click the connector and choose Edit Conditions…, and the step opens with its Condition Checks already scrolled into view rather than on the Alias field with the checks off-screen. The shield on the step’s own tile still marks it as before, and a step with several incoming connectors gets one shield, not one per arrow. A step with no incoming connector, and one folded into a collapsed group, show only the tile shield — there is no arrow to mark in the first case, and in the second the arrow belongs to the group rather than the step. See Seeing Conditions on the Visual Canvas.
Hover the shield to see what the gate would cost. The conditional step and everything downstream of it outline in a dashed highlight — the steps that would not run if that condition blocked — and clear again when you move away. Nothing changes on the workflow; steps upstream are never highlighted, because they run either way. It reads like the preview a disabled group’s chip already gives you, with the wording deliberately different: a disabled group is off, so its chip says how many steps will skip, while a condition is only evaluated when the run reaches it, so the shield says how many would not run if it blocks.
The shield also reports the last run. A plain shield means the step is conditional and either hasn’t run yet or is running now; a shield with a + means it ran on the last run; a shield with a − means it did not. The three differ by shape rather than colour, the tooltip says the state in words, and it all updates live while a workflow runs — so you can watch a run reach a gate instead of reloading the canvas, and answer “why didn’t this step run?” while tracing the flow. The − is an observation, not a diagnosis: a step is also recorded as not run when it is disabled, when a step upstream of it failed, or when it fell outside a partial run’s scope — the toolbar’s View Logs names the reason for each step a run skipped. A step held at a breakpoint keeps the plain shield — pausing there was your decision, not an outcome of the run.
-
Copy and paste steps on the Advanced workflow canvas, links and groups included. Select steps on the canvas — or a whole group, which brings its steps with it — press Ctrl/Cmd+C, and paste them into any workflow, in this project or another, with Ctrl/Cmd+V. The connections among the copied steps come across, the group boxes come across, and the copies land where you point and stay selected so you can drag them into place. A link to a step you didn’t copy is dropped — there is nothing on the other end to attach it to — and the paste tells you when that has happened rather than dropping it silently. A large paste runs in batches, showing progress you can cancel, and never caps or silently drops steps; Ctrl/Cmd+Z right after a paste removes what it added.
One clipboard, everywhere. The canvas, the current steps table, and the older steps table you reach by holding Ctrl (or Cmd) all share it, so it no longer matters which screen either workflow is open in — copying in one and pasting in another used to report There is nothing to paste on the clipboard for steps you had copied seconds earlier. The clipboard is held in your browser, so it survives a reload and is shared by every PlaidCloud tab you have open; switching workspace clears it, and it is never shared between browsers, machines, or people. Two smaller notes: Paste → Add Linked Steps (Advanced) declines a paste into a different project and points you at Append or Insert, since a linked step is a second placement of a step its own project owns; and Copy Selected with no rows selected says so rather than quietly emptying the clipboard. See Copy & Paste steps.
-
A project can now be copied into a project that already exists, not only into a brand-new one, and re-synced against the one it came from. The Duplicate Project action is now Copy Project, and its dialog asks where the copy should go: a new project, as before, or one you pick from the list. Copying into an existing project adds to it — the target keeps its own name, ID, data connection environment, storage defaults, document account, access type, access lists and row-access grants, and only the contents you selected are brought in. Where the copy carries an item the target already has, you choose whether the incoming version replaces it or lands alongside it with
copyappended.This is for taking part of one project into another — a few workflows and the dimensions they use — without exporting an archive and importing it back. You do not have to work out what those workflows depend on: anything you tick brings its tables, dimensions, user-defined functions, sub-workflows and macros with it. A copy into a project you hold no role on, or one locked to prevent changes, is refused before anything is read or written, and a project cannot be copied into itself. See Copying a Project.
Re-sync Into…, on a project’s actions menu, then promotes a later change forward without an export or an archive. PlaidCloud remembers which object came from which, so the comparison runs by that lineage rather than by name: an object an earlier copy renamed still lines up with its original, only what genuinely changed shows as a difference, and you merge the pieces you choose exactly as in an ordinary comparison. This is what lets one tenant hold Dev, QA and Production as separate projects and move changes forward between them. Re-sync a pair that was never connected by a copy and PlaidCloud says so, falling back to an ordinary comparison rather than pretending. See Re-syncing From the Project You Copied From.
-
Row Access — grant security groups the rows they may see, and apply it to your dashboards. Under Identity → Security Group, declare which column on a project governs row access and grant specific values of it to specific security groups. Every project and attribute always shows Granted, Unrestricted, or Denied, so a locked-out group is visible rather than looking unconfigured. See Managing Row Access.
Apply to dashboards then takes a project’s grants and rewrites its dashboard restrictions to match. It matches rather than adds to: a grant you removed has its restriction removed, and a column you stopped governing has its restrictions taken away — so re-applying after a change is how you publish that change, and applying twice does no more than applying once. It needs the same access as editing the grants: Architect on that project, with the project unlocked. PlaidCloud tells you what it applied and what it deliberately left alone — a column drawing its values from a dimension or a typed list is reported as not yet applied rather than silently dropped, as is a table whose governed columns all let ungranted groups see everything.
The first apply on a workspace needs a one-time approval, and there is no undo for it. It takes ownership of the dashboard roles PlaidCloud manages, and the dashboard service keeps no history of role membership to roll back to. So the first time you click Apply to dashboards, a confirmation appears describing it as a one-time, permanent, workspace-wide authorization; a workspace administrator confirms it once, and it records whoever is signed in, so it cannot be given on someone else’s behalf. Until it is given, applying a project is refused and nothing is written to your dashboards. (These actions are also available through the API for automation —
POST /rest/v1/analyze/rls/reconcile, plusGET /rest/v1/analyze/rls/first-write-diffto preview the first-apply role changes andPOST /rest/v1/analyze/rls/first-write-approvalto record the approval.) See Applying Row Access to Dashboards.A query you write yourself is declined, and now says why. Row Access filters the table it is defined against, so a query the caller wrote has no single table to attach that filter to, and PlaidCloud declines to run it rather than return rows nothing has vetted. The message names the project, names the ways of reading the same data that do apply the grants — reading a table by name, and the column and dimension value readers — and says a project Architect can run the query as written, which an Architect is allowed to do because they can already grant themselves every value of every governed column. This covers exporting the results of your own SQL to a file or another database, and typing a row condition into a fan-out step’s “Test row 1” preview. Nothing changes on a project that has not turned Row Access on. See Row Access and Queries You Write Yourself.
Importing a spreadsheet into a Row Access project now works. File imports — Excel, CSV and the like — used to be refused at the very first step, because the same safeguard that declines a query you write yourself was also declining the import’s own table-creation and data-load statements, even though an import reads nothing governed: it only writes the project’s own new table from the file you uploaded. An ordinary file import now runs cleanly on a governed project. The one thing still held back applies only on the interactive import screen: an import whose column mapping you supply yourself — a per-column expression, or a dynamic Excel mapping — is treated the same as free-form SQL, because such a mapping could read another table, and needs a project Architect. Imports run from a workflow are unaffected, since they run under the project’s own service identity. See Row Access and Queries You Write Yourself.
Publishing a table governed by row access is declined. Row Access filters a table by restricting the reporting view it is published as, so a table has to be published for reporting before its columns are governed. Once a column governs row access, PlaidCloud declines to publish — or republish — that table: a published reporting view is read in full by anyone with reporting access, so an unfiltered view of a governed table would hand out every row and bypass the grants. A table that carries no governed column publishes as before, and one already published stays published. Publish the table first, then declare row access on it. See Publishing Tables.
The Data Editor works on a Row Access project, and editing governed data is limited to Architects. Opening a table in the Data Editor on a governed project now shows only the rows your security group is entitled to see — the same filter your dashboards apply, and it holds even when the governing column is not one of the columns on screen. Saving your edits back also works now, where the safeguard used to refuse it outright; because a save replaces the table’s rows wholesale and is not filtered row by row, editing a table that carries a governed column requires Architect on the project, and anyone else is told they need it rather than meeting an unexplained failure. A table that carries no governed column, and any project without Row Access, are unaffected. See Row Access and the Data Editor.
Viewing a table’s data on a Row Access project works, and shows only your rows. Opening a table in the table viewer — its data grid, its row count, and its per-column summaries — on a governed project used to be refused outright with a “statement refused” message and no data appeared. It now applies the same row-access filter your dashboards and the Data Editor use, so the table opens and shows exactly the rows your security group is entitled to see, holding even when the governing column is not one of the columns on screen. Viewing a table as of a past snapshot is not available while it is governed — a snapshot cannot carry the filter — and a project without Row Access is unaffected.
-
Resume picks a workflow back up exactly where it stopped. A run that failed several levels deep — a workflow calling a workflow, or a loop step working through its iterations — used to restart the first called workflow from its opening step, repeating everything in between; on parallel and Advanced workflows Resume restarted the whole workflow, re-running every step that had already succeeded and every sub-workflow they called. Resume now returns to the step or node that failed, at whatever depth it sits, and re-runs only that and whatever was still waiting on it. A loop step resumes the interrupted iteration and skips the ones that completed, a run scoped with Run Selected keeps its selection, and a step that failed is re-run rather than mistaken for one that finished. Re-running a single step on its own no longer changes where Resume goes next. If you had been using Resume on a parallel workflow as a way to re-run everything, use Run All instead.
Resume from top of chain handles the nested case: a workflow that ran as a child of another, invoked by a Run Model step, cannot continue its parent’s orchestration by resuming on its own, so this option resumes the top-level parent and continues the whole chain from where it stopped. The top of the chain is resolved within the same project — a chain that crosses into another project resumes from the top of the in-project portion. See Run a Workflow.
-
A PlaidLink agent can now be assigned to an environment, so switching a project’s environment switches its agents too. A connection already holds a different configuration per environment, so moving a project from your default environment to QA re-points every connection it uses in one action — but the agents that run its remote steps stayed put, and pointing a project at a different machine meant editing every step that named one. Each agent now carries an Agent Group, naming the agents that stand in for each other, and an Environment, saying which one it serves. A step still names a specific agent; the run picks whichever member of that agent’s group serves the project’s current environment. Set the two fields once per agent — there is no per-step change, and no table to keep in step across machines.
Nothing changes until you set a group. An agent with no group serves every environment exactly as today — which is every agent you have until you change one — so a workspace running a single agent is unaffected. Setting a group makes the match exact for every agent in it: a project running in an environment none of the group serves stops with a message naming the group and the environment, rather than falling back to whichever agent the step happened to name. Running production work on a test machine is the failure this prevents, so add an agent for each environment your projects run in, and leave the group blank on an agent that should keep serving everything.
The machine has to agree with the record. PlaidLink listens on one queue for the environment named in its own configuration file, so setting an agent’s Environment to QA in PlaidCloud while its machine is still configured for the default environment leaves it listening where no work is sent — the step waits and then reports that the agent is not picking up the job. Set the environment name in the
environmentsblock of that machine’s PlaidLink configuration at the same time, and restart the service. See Agent Environments. -
Published Table Performance begins its first phase. Open Published Table Performance from a published table in Table Optimizer to see whether its current activity points to columns worth considering for a future layout improvement. Phase 1 passively monitors and recommends; it shows when no change is needed or more activity is required, while your team remains in control of every change. A future release is planned to add automatic optimization for supported tables. See Review Published Table Performance.
-
You can now see how far along a new workspace is, instead of waiting to find out — and its service links appear only once there is something to open. Creating a workspace takes several minutes, and the list used to show a status you could not act on: a workspace that had stalled part-way looked the same as one still working.
The workspace list gains Created and Provisioning columns, and the workspace details dialog gains a Provisioning tab carrying the same information plus the service addresses currently published for that workspace. Provisioning reads
provisioning,running,failed,paused,trashed, ordeleting. A workspace sitting on the same phase for more than about half an hour has stalled, and one readingfailedhas stopped — now you can tell, with the phase to quote to support. (One stall is gone entirely: a workspace created without the optional backup feature could stop part-way through setup and sit on Activating forever. It now completes normally.)The Home, Dashboards, SQL and Logs & Metrics links follow the same readiness. They used to show on every workspace and were built from a fixed address, so a workspace hosted in a different data center got a link that went nowhere, and a workspace still being created got one that could never have worked. Each link is now the address PlaidCloud actually publishes for that workspace, and the icon is present only when the workspace is running and that service is switched on for it. A paused workspace shows none of them, and neither does one whose setup has not finished.
One thing worth knowing: a workspace can look healthy in deployment tooling while still not being usable, because deployment finishing is not the same as the workspace finishing its own setup. What you see here reports the workspace’s own setup, which is the one that decides whether you can sign in. See Provisioning Status.
-
PlaidCloud now offers its own geocoding API, so you can look up coordinates for an address, resolve an address from coordinates, get type-ahead suggestions, and look up a place record — all as REST calls, without a Google or Mapbox account. It covers free-text search, structured (field-by-field) search, reverse geocoding, autocomplete, and place lookup, with a response that tells you how precise each match is. Every match also carries a geohash, and can carry a Plus Code as well, computed straight from its coordinates — the same location codes the geocode workflow step produces at its default settings — so you can bucket or share a result’s location without a separate lookup; pass
location_codes=noneon a request to turn them off. Data comes from OpenStreetMap: strong in well-mapped regions, more variable elsewhere, and its own attribution has to be displayed alongside anything you show a user. See Migrating From Google or Mapbox Geocoding. -
PlaidCloud can also route by drive time, as an opt-in preview. New REST endpoints draw an isochrone — the area reachable within one or more time breaks from a point — and rank a set of candidate destinations by actual drive time from one or more origins, rather than straight-line distance. Both run over a self-hosted routing engine on OpenStreetMap roads, with costing for car, truck (height, weight, and length limits, so a route can steer around a low bridge or a weight-restricted road), bike, and pedestrian; hazmat routing isn’t supported. The service runs on a small, shared routing pool, so it’s off by default, reaches only tenants who’ve opted in, and is offered best-effort with no SLA — an occasional busy-pool response is expected, not a fault to chase down. See Drive-Time Routing API.
-
The geocode workflow step now adds a location code to every row. Alongside the coordinates it already returns, the geocode and geocode reverse steps append a geohash column by default — the compact code used across data tools (Elasticsearch, Redis, Lucene), whose prefix property makes
GROUP BY LEFT(GeocodeGeohash, n)an instant way to bucket points by proximity. The step’slocation_codessetting also switches on an optional Plus Code column (the human-shareable form used by Google Maps), and a separategeohash_precisionsetting tunes how fine the geohash is. Both codes are computed locally from the coordinate — no extra lookup, no external service. See Geospatial Analytics. -
Make Grid and Poly-Split are now configurable in the designer. The two spatial steps already converted from Alteryx and ran, but selecting either from the step palette gave you no options to fill in — you had to author them through the API or MCP. Make Grid now has a form for the geometry column, grid size and units, whether to build one grid per object or one grid over the whole extent, and whether to clip cells to their polygon; Poly-Split now has a form for the geometry column and whether to split to points, regions, or regions with their holes broken out. See Spatial Make Grid and Spatial Poly-Split.
-
A guided builder for allocation dimensions. Setting up a rule-based allocation used to mean hand-building its assignment dimension node by node before a step could point at it. The Dimensions view now has a New Allocation Dimension entry that walks you through it: name the dimension and pick the source table your rules read and the driver table they spread against; tick the source columns that act as rule filters — attaching a dimension to one that doesn’t have a relationship yet, or honoring the one it already has; say which driver columns name and value each driver, and which target columns the amount is spread across; then fill a flat grid of rules, each a set of source-filter values paired with the driver it uses. Finish, and the whole dimension is created in one step, ready for an allocation to reference. The dimension is authored on its own, so one dimension can serve many steps, and it carries a split icon in the dimensions tree to set it apart from an ordinary hierarchy. The builder appears where your workspace has the feature switched on, for anyone with permission to create dimensions. See Creating an Allocation Dimension.
Changed
Section titled “Changed”-
PDF project reports render faster and come out slightly shorter. Every heading, paragraph and block of code in the report was individually wrapped in a “keep this together on one page” group, and each step’s block was then wrapped in a second one around all of them. The inner groups changed nothing you could see — a single heading or paragraph always fits somewhere — but the layout engine still measured and re-measured each one, which is where most of the time went. They have been removed; the group that keeps a whole step together is unchanged. One visible difference: a long step memo or block of SQL that does not fit in what is left of a page now continues onto the next page instead of being pushed onto it whole, so reports lose a little trailing white space and typically run a few per cent shorter. The contents page and its links are unaffected, and nothing else about the report changes.
The report also collects its data with fewer round trips. It read each workflow’s steps, variables and diagram one after another, and each workflow one after the last, so a project with many workflows spent much of the wait queueing requests that do not depend on each other. Those reads now run together, bounded so a large project cannot flood the service. Nothing about what the report contains changes — only how long it takes to produce.
-
A cost-trace answer covering several value columns now says how those columns relate, and shows what each one moved between. Asking why programme margin fell returned margin down 19.9% next to cost down 10.4% and revenue down 11.5% — which reads as margin eroding at nearly twice the rate of costs. It isn’t: the three balance exactly, margin’s change being revenue’s less cost’s, and margin starts from a far smaller amount than either, so the same dollar amount is a much larger percentage of it. Neither fact was on the page, and the one column whose opening and closing amounts were shown was the only one that didn’t need them — so a reader wanting the second had to work a starting amount back out of a percentage rounded to one decimal. Every column now states the two amounts it moved between, so you can check the balance at both ends of the period rather than only on the changes, and a line above the block states that the columns balance to the cent at both ends and which of them starts from the smallest amount. It says nothing about how your model is built: whether one column is calculated from the others isn’t something the answer can see, and every rearrangement of a balance is equally true, so naming one as the calculated column would claim something the arithmetic doesn’t support. Where a column starts from a negative amount, or where the smallest starting amount isn’t much smaller than the next, the balance is stated and the comparison of sizes is left out. Answers covering a single value column are unchanged, and no figure changes. See Analyzing Allocations with AI.
-
A cost-trace answer covering several value columns now says when the column it leads on is the one it explains least well. Each step of the trace already named the biggest single factor behind a column’s move and how much of the move that factor explains, but those figures appeared once each at the end of the answer and nothing compared them. On one automotive model the answer opened on
marginand gavemarginthe only member breakdown on the page, while the trace at the bottom put 81% against the cost move, 79% against revenue and 60% against margin — so the figure the whole answer is built on was the one whose story holds together least, under a single rating covering all three columns. The confidence line now closes by naming the column the answer leads with, saying it is also the one a single factor explains least of, saying whether it is the same factor in each case, giving what it explains for each column, and saying that the rest of each move is carried by the other factors and the interaction between them rather than being missing. It says nothing where the spread is small, where a column’s split is being withheld, or where two columns tie at the bottom. No figure changes. See Analyzing Allocations with AI. -
The two “what if” allocation questions now explain their limits in words you can act on. Asking an AI agent what happens if an input rises, or what happens if a driver is reweighted, returns estimates plus short notes saying what those estimates leave out — and unlike a full cost-trace answer, those notes are the only prose either question produces, so whatever they fail to say is not said anywhere. They had been written as shorthand. One opened by saying a driver change “does not inject value”, which reads as changing this driver does not matter when the opposite is the point — a driver reweight changes which parts of your business are charged, which is the whole subject of an allocation. One ended on an internal release marker, naming a capability you cannot ask for. One said two lists were “unaffected” by a row limit, where what is true is that the limit did not change them. One pointed at a setting no analyst can change, without saying who can. And one told you a share above 100% was “mathematically correct, not a data error” — defending the arithmetic while saying nothing about the thing at risk, which is that a share above 100% has stopped being a share. Each note now names what it is about, says what the figures do cover as well as what they exclude, and ends on something you can do — including pointing you at the other question when the one you asked cannot be answered from where you are. No figure changes, and no cost-trace report text changes: these notes travel with the answer rather than inside its narrative. See Tracing Allocations.
-
A cost-trace answer’s member table now says how much of the change is on the page when it is showing only the largest movers. A heading of “Top movers by account, sales_document (largest shown)” and a heading of “All movers by account” look alike and carry completely different weight: the second adds up to the change exactly, and the first can be a small and mixed corner of it. On one model twenty rows, none of them as much as $110,000, sat under a fall of $9,321,592.41 and came to $169,230.35 between them — thirteen down and seven up — so the table read as a picture of the fall while accounting for under two per cent of it, and “(largest shown)” was the whole of the warning. The table now carries a line above its rows, so it travels with them when they are copied: how many of the rows shown move each way, what their sizes add to, what they come to on balance, what the change itself is, and that the difference is in the members not shown. Both totals are given because either alone is read as the other — the net on its own reads as “these are noise”, which is wrong when their sizes add to five times that, and the gross on its own reads as a net. No percentage is given, deliberately: the rows shown can move against the change or outweigh it, so a share of it turns negative, exceeds a hundred per cent or rounds away, where two amounts beside the change mean one thing in every result. A table that shows every member is untouched. See Analyzing Allocations with AI.
-
The step form now opens read-only when you cannot change steps, rather than letting you edit and failing at Save. If your role lets you open a workflow but not modify it, the form used to open fully editable — you could work through a step’s settings and only discover the problem when Save was refused, losing the edit. It now opens with its fields disabled and its write buttons hidden, so a step’s configuration is still there to read, but nothing invites an edit that cannot be kept. This applies wherever the form opens: the workflow table’s edit (pencil) icon, the Visual Canvas, the project Steps grid, the New Step menu, and after converting a step. Nothing changes for anyone who can already edit steps, and what the server accepts is unchanged — this closes the gap between what the screen offered and what it would accept. See Why a Workflow Might Not Be Visible.
-
The Visual Workflow Designer gets a folded step palette, panes you can collapse and resize, and a dark canvas.
The step palette is organized into folders. Every step type used to sit in one long list you scrolled through; steps are now filed in ten folders that start closed, with your favorites still pinned above them. Folders are shaded by depth and draw a guide line down everything inside them — click a guide to close that folder without scrolling back to its heading — they open and close with the same +/− box the dimension screens use, the heading of the folder you are reading stays pinned to the top as you scroll, and Expand all folders / Collapse all folders sit in the palette heading. Filter… searches everything at once, open or closed, and lists each match under the folder it came from. Clicking a step adds it: it appears near the top left of the canvas, already selected and ready to drag, the row flashes so you can see the add landed, and Delete removes it if you picked the wrong one. Dragging from the palette still drops a step exactly where you let go.
The whole palette is keyboard operable and navigable with a screen reader. Tab into the list and the arrow keys move through it, Left and Right close and open folders, Enter adds the step you are on, and Esc returns you to the filter box. Each row reports whether it is a folder, whether that folder is open, and how deep it sits. See The Step Palette.
The palette and the Inspector fold out of the way, and both can be resized. Click the chevron in either header, double-click the divider beside either one, or press
[for the palette and]for the Inspector, and the pane folds to a narrow rail with its title running down the side; the collapsed Inspector rail keeps showing the name of the selected step, and clicking anywhere on the rail opens the pane again. Either pane can also be dragged wider or narrower by its divider. Widths and collapsed states are remembered per browser and shared across workflows rather than saved per workflow — each pane separately, so a change to one does not disturb the other, and canvas windows already open keep their layout until you close and reopen them. See Collapse and Resize the Palette and Inspector Panes.The canvas follows the Dark theme. Working in Dark used to leave the canvas and everything on it — step tiles, connectors, notes, highlights, containers, the minimap, and the palette, Inspector and Data Preview drawer around it — drawn light against an otherwise dark application. They are now drawn for a dark background, with run-status colors and label text chosen to stay legible against it. Diagrams you export stay light whichever theme you use, because a dark diagram is right on screen and wrong on paper, so Export as PNG and Export as PDF read cleanly when printed or pasted into a document. See Dark Theme.
-
Dashboards drop their cached results the moment a table is republished, and cache for an hour by default. A dashboard caches each chart’s results so repeat views don’t re-query the warehouse, and those results were meant to be discarded as soon as a workflow run republished the underlying table — but the discard never took effect, so a chart could keep serving pre-refresh numbers until its cached result expired on its own. Republishing now clears them straight away, and the next person to open the dashboard sees the new data without forcing a refresh.
Because of that, the cache no longer has to expire quickly to keep a dashboard current: the default lifetime is raised from five minutes to an hour, and you can set it higher still to match how often the data actually changes — in seconds on a database, under Advanced → Performance → Chart cache timeout, or on a single dataset under Settings → Cache timeout. On a table that reloads overnight, an hour or a day means a morning’s dashboard views are served from cache instead of re-querying the warehouse, which is where most of a slow dashboard’s time goes. One case is worth checking: if a table is written to by something outside PlaidCloud, nothing tells its dashboards to drop their cache, so the lifetime is all that refreshes them — those can now be up to an hour behind rather than five minutes, so set a shorter lifetime on those datasets. See Dashboard Caching.
-
The dashboard list now respects per-dashboard restrictions set in the dashboard service. A dashboard can be restricted there to particular roles. Where one has been, PlaidCloud now lists it only for people holding one of those roles, along with its owners and dashboard-service administrators — previously the restriction applied when you opened the dashboard but not to the list, so a restricted dashboard stayed visible to everyone who could reach its project. A dashboard with no such restriction is listed exactly as before, to exactly the same people, and no dashboard is restricted this way today, so nothing disappears from your list as a result of this change. One thing to know: your dashboard account has to exist before a restricted dashboard can reach you — until then restricted dashboards stay hidden while unrestricted ones are listed as normal, so open any dashboard once from PlaidCloud and the restricted ones you hold a role for appear. See Which Dashboards You See.
-
Dashboard accounts follow your PlaidCloud membership, and are managed from PlaidCloud. Inside the dashboard service, adding or editing a user account directly is now limited to administrators, and the screens for creating and editing pending registrations have been removed. Nothing changes about how people get to a dashboard: your dashboard account is set up for you the first time you open one from PlaidCloud, and what you can see there follows from your workspace membership and security groups. Accounts made directly in the dashboard service are not connected to your workspace membership and are easy to leave behind. See Managing Workspace Members.
Three ways the two used to drift apart are fixed. Changing a member’s email address now updates their dashboard account too — the change saved in PlaidCloud but never carried across, and nothing reported an error, so anything looking a person up by email stopped finding them, leaving their reports account orphaned under an address they no longer used. Re-creating a member no longer resets their reports and dashboards access: removing a member has never deleted their dashboard account, so removing someone and adding them back — a rehire, a corrected email address, undoing a mistaken removal — used to reset that leftover account to the most basic level, discarding administrator access, elevated report-building roles, and any role controlling which rows a report shows them. And a member with two dashboard accounts differing only in capitalization can sign in again: sign-in matched both, could not tell which was meant, treated the person as a first-time arrival, and left the dashboard sign-in page flickering about once a second without ever getting in. Sign-in now settles on a single account — active first, then exact capitalization, then oldest — and two such accounts can no longer be created. If a member’s email was changed, or they were removed and re-added, before this release, the two records are still out of step and must be reconciled by hand; the capitalization case needs nothing cleaned up.
-
Excel exports are around twice as fast, hold their memory flat, and tell you up front when the file cannot be written. A large export previously held the whole result in memory while it built the file, so the biggest exports were also the ones most likely to run out of room and fail; the file is now built as the data is read, so the memory needed stays flat whatever the row count and a typical large export finishes in roughly half the time. The resulting workbook is unchanged, apart from one fix: a date column shows as a date again rather than as a number like
44355— date columns were being written without their date formatting, so Excel displayed the underlying number. Columns holding both a date and a time were not affected; re-run the export to correct an existing file.An export too large for a worksheet now stops immediately and says why. A worksheet holds at most 1,048,576 rows and 16,384 columns, and a step asking for more used to spend the whole export producing a file Excel then refused to open. It now checks before it starts and names CSV and Parquet as the alternatives; very large exports that exceed what the file format allows are reported the same way. See Export to Excel.
-
AI agents connected over MCP read your workspace with far less of their capacity spent on the reading. Listing and lookup tools return the first 25 matches per page rather than 50, an agent can name the columns it wants with
fields=[...]instead of taking the whole record, and where every row of a result carries the same fields it comes back column-oriented — the field names once rather than once per row, around 30% fewer characters on typical listing traffic. So a routine “list the tables in this project” costs a fraction of an agent’s limited reading capacity, leaving more room for your actual question. A page that was capped now says so explicitly, so an agent asks for the next page instead of treating the first 25 as the complete answer, and asking for a column that doesn’t exist returns a clear error naming the columns that do. Nothing is out of reach: raiselimit, or page with the cursor. Connected agents read the column-oriented shape without any prompting from you and no value changes on the way; if you read these responses from your own code, handle both shapes. See Keeping Results Small and Column-Oriented Results.The AI assistant carries a leaner tool catalog too. The list of available tools it loads on every turn is about a third smaller with no loss of capability, and a batch of tool descriptions that told it the wrong thing — naming a tool that doesn’t exist, describing an optional field as required, quoting an error the platform never returns — has been corrected, so it wastes fewer turns on requests that were never going to work.
A query an agent runs now returns at most 10,000 rows, and says when it stopped there. There was no limit before, and an agent asking for a very large result made everyone else on the same server wait while the answer was prepared to send — reading the rows was never the slow part, packaging them was, and that grew with the size of the result. Results are capped, the reply marks itself as cut short so the agent narrows its query rather than assuming it saw everything, and the packaging step is far cheaper at every size. This applies to raw SQL an agent runs and to query plans it asks for. Nothing changes for an ordinary request, which is comfortably under the cap; if you genuinely need more rows than that, an export is the right tool rather than an agent conversation. See Keeping Results Small.
And one agent can no longer crowd everyone else out by asking for a great many things at once. An agent can bundle several requests into a single call to save round trips, and there was no limit on how many it could bundle, nor on how many of them ran at the same time — so one bundle could occupy the machinery every other person’s work queues behind. A bundle now holds at most 100 requests and runs a bounded number of them at a time; the rest wait their turn rather than being refused, so a legitimate bundle still completes without crowding out the workspace. A bundle over the limit is refused with a message saying so rather than quietly running part of it. Bundles can no longer be nested inside one another, which never saved anything a flat list does not, and the recipe that pages through a long listing now stops after a set number of pages and says it stopped early. See Batching Requests.
-
Allocation and cost-trace answers say more, claim less, and repeat. Asking an AI agent what drove a change in an allocated cost returns a far more usable answer, across every part of it. Nothing about your allocations, and almost no figure in these answers, has changed — what changed is what the answer states, what it admits it cannot state, and how consistently it does both. See Understanding the Answer, Honest Answers and Tracing Allocations.
It states the figures behind the percentage. An answer leading on a single figure now gives the amounts it moved between — “net_contribution fell 23.5% (from -$12,917,012.01 to -$15,957,089.93)” — so a direction word can be read against the figures rather than on its own, which matters most where the value is negative and “fell” reads as a profit shrinking when it is a loss getting bigger. A useful side effect: consecutive questions about the same slice join up, one answer’s closing figure being the next one’s opening figure. An opening line reporting offsetting rises and falls carries the pair too — “the net barely moved (3.7%, from $85,472,090.25 to $88,668,890.26), but that hides large offsetting movements” — because those two figures are the pool’s rather than the net’s, so they make that line’s point more plainly rather than softening it: $3.2M of movement inside an $85.5M pool is visibly nothing, where “barely” alone was a judgement about a base the answer never showed. It still sends you on to a single member. An answer reporting no material change gains the same pair. Only a figure that is genuinely unavailable is left unstated — a question the agent declines to attribute, or a combined total that could not be read — where nothing is given rather than a placeholder.
A table recombining several allocation branches states its combined total. It was the one answer opening with no money at all — “across 4 recombined branches, all 4 fell” — on the reasoning that a recombined table has no single total to state. It has one: it is a real table, and the agent reads its total straight off it, so the line now opens “the combined total fell 58.0% (from $34,621,164.20 to $14,535,705.89)” and the year-on-year comparison resolves for these answers as it does for every other shape — which on one model surfaced a reversal it could not previously state at all, this year’s fall being 89% the size of last year’s rise. The total is read from the table rather than by adding the branches up, because a branch reaching the recombination by more than one route is listed once and counted more than once in the table. Where the two do not agree the answer says so and names both — “the branch figures shown ($12,231,623.56) do not account for the combined change of $25,082,057.48” — and where the total genuinely cannot be read, the opening line reads as it did before and the answer states which condition stopped it. Each branch’s line also states the two figures its change moved between, and an answer covering a single branch reads “1 allocation branch” rather than “1 branches”.
It names the driver behind its commonest explanation, and whose pool the share is of. “A slice’s share of the pool shifted” — of what, driven by what — is now “the shift in this slice’s share of the pool (split on the headcount driver; this slice’s share of the cost pool went 26.5% to 18.2%)”. That is the difference between a fact and a lever. On a table with several value columns each column has its own pool, and the line used to say only “pool share”: one programme over one pair of years printed three different shares — 26.5% to 18.2%, then 25.9% to 18.1%, then 21.9% to 16.9% — with nothing on any of them to say which pool each was a share of, so a reader asks how one programme can have three shares of one pool and concludes the answer is broken. Each now names its column, on single-column answers too, because “pool share” is a question there as well. The driver is named without figures where the share is not a sensible percentage, and a step with no driver has none to name.
It grades confidence on the column you are reading, not just on average. The closing confidence line was an average across value columns weighted by how much each moved — and a summary column, being the difference between the others, is almost always the smallest mover and the one you act on. The weaker column is now named first: “medium for the net_contribution column (mostly clean); high overall across 4 columns”. A table recombining several allocation branches is graded the same way, where a branch’s own confidence previously appeared nowhere at all: the weaker branch is named — “medium for the Allocate Support Costs branch; high overall across 2 branches” — and its line in the per-branch breakdown carries its level too. A level marked against a column or a branch now always means weaker than the answer overall, never stronger: on a model whose overall level was medium the mark used to land on the largest faller, labelling it “high”, while the column the answer led on carried nothing. Where the columns or branches agree, the line now states how many it is about — see the next entry.
It says what the confidence is of. That closing line named a level and, often, a reason, and said nothing about what either was about. Three things follow from that, all fixed. It now names the breakdown it rated — “Confidence in this breakdown by lob” — which matters most when you follow an answer’s own suggested next step: on a banking model the same figure cut by line of business rated medium and, cut by branch as that answer recommended, rated high. Both ratings were right, because cutting differently changes which members offset each other, but with neither line naming its cut the pair read as one number rated twice, the second reading as “we looked again and it’s fine”. It now states its scope where the columns agree — “medium across 3 columns” rather than a bare “medium”, which on a table with several value columns was a rating of no stated number of anything. And it now gives a reason only where every column gives the same one: on an automotive model the line read “medium (mixed residual)” where that residual belonged to
cost, a column that had moved 0.2%, while the figure the answer led on was a 38.0% fall inmargin— so a reader discounted the headline on the strength of a qualification that was not about it. The per-column reasons were always in Honest limits, each against its own column, and still are. Where a group of columns is both the weakest and shares a reason, that group is named. A single-column answer is unchanged.A confidence word inside the trace never outranks the answer’s own. The step-by-step account at the end of an answer stamped each step’s own level on its caveats, in the same vocabulary the answer uses for itself. So a recombined-branch answer opened “low (partial attribution)” and then said “Caveats (high confidence)” twice, eight lines further down, in the block where the figures are — one word, two scopes, nothing on the page saying so, and a reader scanning for the numbers left with the wrong one. A step now states a level only where it is weaker than the answer overall, which is the rule the per-column and per-branch marks already follow; otherwise the line reads “Caveats: …” and the caveat itself is untouched. Separately, where two things hold a confidence down, the line now names both: an answer held at medium by unevenly populated periods and by part of the upstream chain it could not attribute printed only the first, so a reader who skimmed to the label never saw the more serious half, though the answer’s own opening summary said both. It now reads “medium (uneven period coverage; partial attribution)”.
A complete list of movers no longer calls itself the top of a longer one. A breakdown by a dimension was headed “Top movers”, which tells a reader there are more they cannot see — and usually there are not: where a dimension has a handful of members the list is all of them and the figures add up to the whole change. So a reader either hedged a conclusion that was in fact complete, or went looking for rows that do not exist. The heading reads “All movers” where the list is complete and stays “Top movers” where it genuinely was cut short — which the answer already said, in a note that appears only on lists that had been cut, so the complete case was marked by nothing at all. Where the answer was never told whether the list is complete, it stays “Top movers”: vague is the right answer to not knowing.
A lowered confidence says what was less than clean, what the overlap is between, and how much it varied. “Mostly clean” is a label, not a reason, and on an answer whose only other note is withheld it was the whole of what a reader got — confidence lowered, nothing to act on. It now names the overlap that caused it: “mostly clean — 16% of the move is interaction between the change in the pool total and the shift in this slice’s share of the pool”. The two things it sits between are read from the answer rather than being fixed wording, because they are not always the same two: an answer following the money through a slice of a pool splits it differently from one tracing the whole pool at once, and an answer about a step that reassigns a dimension has three of them. So that clause names what the step-by-step account below it names, and can be checked against it. And where an answer covers several value columns it now gives the figures they measured — “8% at the lowest and 12% at the highest of the 3 columns’ own moves” — instead of one column’s figure standing for all of them: on an automotive model it quoted 8% over columns that measured 8%, 9% and 12%, while the account below put 81%, 79% and 60% against those same three, so the single figure was visibly not about all of them. Where the columns measured the same overlap, the single figure states as before.
A movement that is entirely the size of the row shortfall between the two periods says so, on the line you forward. Two periods can hold very different numbers of rows — usually because the later one has not finished loading — and an answer has always warned about that in general terms. It never put the two proportions side by side, which is the only comparison that settles it: asking why German cost fell returned “it fell 58.0%”, over periods holding 1,755 rows and 754, with the money falling in almost exactly the same proportion, under a warning that “part of this change may reflect incomplete data”. The whole 58% was consistent with a half-loaded period, hedged as “part”. The note now reads “the later period holds 43% of the earlier period’s rows, and the change reported here leaves its value at 42% of the earlier period’s — the same proportion, so this movement is what the row shortfall alone would produce”, and the opening line carries it too, where a recombined-branch answer stating a $20m fall previously carried nothing at all. It is explicit that this does not settle which — an incompletely loaded period and a genuine fall of that size look identical on that measure — so it asks you to check the load rather than telling you the movement was not real. Where the money did not move with the rows the answer says that too, and where any part of an answer covers an evenly populated period pair the opening line is left alone, so a real movement is never disowned.
The whole-pool warning appears only where there is no breakdown, and the pool-conservation note is separate from it. The warning telling you to scope to a member was still printing above breakdowns the answer had just produced — on a tax model, five lines above a four-entity breakdown. It now appears only where it is true; the columns and stages that genuinely have no breakdown of their own keep it, because for them it is the useful half. That warning also used to bundle a second statement — that the pool total always credits the incoming value rather than the driver, which is a property of how allocation conserves the pool and not a finding about any member — and dropping the pair together left “the value coming in explains 100% of the move” printed next to “account=LAE drove the move”, with nothing in the answer to settle which to believe. They are two separate notes now, so picking a breakdown drops only the one it disproves.
A search that found nothing still names the member behind the figure it quotes. It read “the strongest candidate was branch, its largest member accounts for a share shift worth ~45% of that column’s change” without ever saying which member — the one place the answer withholds a name being the one place the finding is uncertain and you most need to judge it. It also left the answer’s own warning that a follow-up may lead with a different member impossible to check.
A label describing how a figure was measured no longer reads as a cause. Where a member’s own change is larger than the whole net movement, the answer said it “drove the move by its own change” — words that named which of two measurements had been used, and which a reader took as the reason the money moved. On a tax model the answer’s own recommended next step said otherwise: 85% of that same member’s change came from its share of the cost pool shifting under it, which for an intercompany charge is the difference between an entity’s own conduct explaining the charge and the allocation basis moving beneath it. Both answers were right; only the first read as an explanation when it was a description. That line now states what the figures show — “its own change is larger than the whole net move” — and reads with, rather than against, the note beside it that other members partly offset. The wording for the other measurement is untouched and no figure changes.
Its year-on-year note says how big this move was against last year’s, and what last year’s actually was. The note gave one word — normal, elevated, extreme — where a year of large rises and falls that nearly cancelled leaves a tiny net, and an ordinary year after it comes out as a very large multiple. It now reads “1325% the size of last year’s move in absolute terms, in the opposite direction; last year moved +$1,792,719.72”, says that the comparison is between amounts rather than rates, and states outright when the two periods moved in opposite directions — including where they are too far apart for a ratio to be worth quoting, in which case you get the direction, and last year’s move, without a multiple. Where there is no prior year at all, the answer says there is no baseline and now leaves the amount beside it empty, instead of filling in the whole of the current year — which read on one insurance model as last year having moved $380.9M against this year’s $1.79M, a collapse that never happened.
It says which measurement each number is. The figure an answer opens with is a shift in share of the pool; the breakdown it suggests you run next reports each member’s own change. Both used to be described as a percentage “of delta”, so one model gave 71% and 98% for the same programme, same column, same period, one click apart. Each measurement is now named where it appears, including where the search found nothing and quoted only the closest field, and the suggested next step warns you to expect a different number for the same member. Neither figure changed — only what they are called.
A “one member drove this” line now names its measurement too, so it can be read on its own. Naming the measurement used to happen only in the answer you started from, which is enough while you read that answer and its follow-up together and not enough for an answer reached on its own — a bookmark, a link someone sent you, a colleague pasting the text, or an assistant that ran only the second question and has no memory of the first. Such a line read “branch=DIGITAL = 63% of delta”, where the only clue to which of the two measurements it was were the words “of delta”. Both now say: “63% of the delta, its own change” against “71% of the move by its shift in share of the pool”. Four words on a line that appears throughout an answer, which is about 1% of a typical answer’s length — a separate note on every stage would have cost far more for the same sentence.
And where it cannot sensibly print that percentage, it no longer promises a comparison you cannot make. When one member’s shift is larger than the whole net change — routine where large rises and falls cancel out — printing “1166%” would be absurd, so the answer described it in words. But the sentence after it still said the breakdown it suggested “will not match this figure”, and no figure had been printed: following the advice showed a list identical to the one already on screen, so a reader who checked the warning found nothing to check and learned to distrust these notes generally. The size is now given as a multiple — “by more than the whole net change in share-shift terms (11.7×)” — so there is something to compare against. Where even that cannot be stated, the sentence keeps its explanation of what the two measurements are and drops the promise that they will visibly differ.
And on a table with several value columns, that line names the column its figure is measured on. Each such line reports one member’s share of one column’s change, and the column is already on the line — 60 characters earlier, at the start of the step — where it loses every time to the table of rows in front of the reader. On a banking model the step-by-step account said “branch=REGIONAL = 70% of the delta” twice while the only breakdown on the page was of a different column,
net_contribution, where REGIONAL came last of four with about a fifth of the movement. Both figures were right, and read together they look like a contradiction — and the reader who resolves it the wrong way takes REGIONAL to the wrong branch manager. Those lines now read “70% of the funding_charge delta, its own change”. Whether to name the column is decided across the whole answer rather than line by line: two lines quoting the same percentage about different columns — “63% of the interest_income delta” and “63% of the net_contribution delta”, eight lines apart — are the same confusion with no table involved, and naming one but not its neighbour is worse than naming neither. So either every such line carries its column or none does. An answer covering a single column, and one whose lines are all about the column it broke down, are unchanged.It says how much the chosen breakdown won by, and warns when the next step answers on a different column. Where you do not name a field, the agent picks one and says it is “the strongest cut among the dimensions searched” — without ever saying how much strongest, so the field it beat disappeared. On one insurance model the winner scored 11.66 and the runner-up 5.86: half as much, a genuine second story, and visible nowhere in the answer. It now reads “On that measure account scored about 2.0× the next candidate, line” — a comparison rather than a second percentage beside the first, since two percentages measured differently side by side is the confusion these notes exist to prevent. A search that could only score one field says so instead of referring to a runner-up that does not exist. Separately, on a table with several value columns the suggested breakdown answers on the column the answer leads with, which is not always the column the agent searched: one model found its story in
cost, offered “the breakdown the auto-discovered cut is based on”, and returned a list aboutmarginled by a different programme with a top figure an order of magnitude smaller. Both answers were right, and someone following the suggestion would reasonably conclude one of them was wrong. The suggestion now names both columns and says the leading member can differ too, not just the percentage. Where the answer covers a single column the two are the same and the wording is unchanged.It describes the table and column you asked about. A trace through several allocation stages printed the member breakdown from the deepest stage rather than the table you named — a headline reporting a $9.3M fall followed by movers adding to $16.2M. On a table built from several branches, the row-count note reporting how comparable your two periods are was taken from the largest branch alone, and an answer covering several allocations named only the first while counting each value column as its own branch. Branches are counted as branches now, and a branch whose own columns move in different directions is reported as having moved both ways rather than being assigned one. A result with several value columns now always opens on the same column, and every note about the automatic search names the column it ran against. All of these now describe the table in the headline, at the same scope, adding up to the headline figure.
It declines instead of answering anyway. Naming a breakdown field the table doesn’t have is refused outright, listing the fields it does have, rather than returning a confident answer with the breakdown quietly missing; naming a period column it doesn’t have is refused the same way, rather than going ahead and reporting only that it couldn’t total the figures, which read as a passing glitch worth retrying when retrying could never help. Driver what-ifs are checked the same way, and you can still leave the period column unset and have it detected for you. Further up the chain the rule is deliberately different: a field added by an allocation only exists downstream of it, so where a field is genuinely absent from an earlier stage the trace groups by the fields that stage does have, telling you which it left out, rather than losing that stage’s breakdown. And where a breakdown is missing for any other reason, including a passing warehouse fault, the answer says so and offers a retry — the totals are measured and unaffected; it is the per-member detail that is absent, not wrong.
A field that is blank on every row is reported as unfilled instead of as a change perfectly concentrated in one member, and where the best explanation of a change is its unfilled rows, the answer says how often that field carries a value at all — “
cost_centrecarries a value on 12% of the rows in the periods compared” — because that finding means something quite different on a field that is nearly always filled in. Very sparse and very complete fields read as fewer than 1% and more than 99% rather than as 0% or 100%, neither of which can be true in that case. A total that crossed zero names the sign change and drops the meaningless percentage. Where the check that bounds the automatic search fails, the answer says the search was not run — a limit on the search, not a finding about the data — rather than searching every field on the table in silence, and tells you to name the field you want examined, which works whatever the cause. Where a knock-on estimate could not be worked out for a step, that result carries no figure at all instead of being reported as receiving the whole change, and everything below it is left out of the totals and named as missing. A result measured from only part of what writes it says so and names the step that could not be read: the figure is a real measurement of what could be read, so it stands, but it is not the whole result and should not be read as a floor.Its confidence and its warnings hold up. A trace with unattributed stages in the middle is held to medium at best rather than reading “high — clean attribution” off the final stage. A warning raised by an earlier step in the chain reaches Honest limits rather than sitting as a fragment inside the trace. An answer that picked its own breakdown field now carries the offsetting-movement warning that the same question already carried when you named the field yourself. The note saying a list of movers was cut short travels with the list, so asking for a shorter answer no longer changes what it claims. A note raised by several of your value columns names every one it applies to — “Columns revenue, margin: …”, or “Column revenue (also raised by margin): …” where the figures shown belong to one of them — rather than opening with a single column’s name and leaving the others reading as exempt. A change whose pieces overshoot the total by a few pence is no longer described as partly offset by countervailing movements that were not there. And the check that confirms a reworded answer kept its warnings no longer passes a rewrite that dropped one because a column in your own model shared a word with it.
It picks a breakdown field properly, and offers next steps you can actually run. The score deciding which field best explains a change was capped at 100% before candidates were compared, so on one insurance model three fields scoring 1166%, 586% and 246% all looked identical and the reader was asked to choose. The cap is gone: the field is named, with the movement behind it. Where fields genuinely are close, each is offered as its own suggestion; where nothing cleared the bar, the answer says it searched, says the change reads as a broad move rather than something concentrated, and offers the closest field it found. Where large rises and falls cancel out, the suggestion to narrow to one member now comes first and names the member whose own rise or fall is larger than the headline change — except where naming one would promise more than the answer measured, as when the movement sits in rows that have no value for the field, or is a shift in a member’s share of the pool rather than the member’s own rise or fall; there it still offers to narrow but names no member, and the breakdown stays first. An answer scoped to a single member no longer advises you to scope it to a single member. The two situations that used to offer no next step at all — a total that crossed zero, and a stage that could not be aggregated — now carry one, the second naming the table to check and the likeliest cause, a period column missing from that stage’s table. One case still offers none: where an independent read of the driver table disagrees with the realised split, the useful move is to inspect that driver table directly, which is a separate request rather than an adjustment to this one. An answer spanning several recombined branches now offers one too, naming a branch and the table to trace to follow it on its own — the agent does not trace back past the point where branches meet, so that is where it hands the thread over. The branch offered is the largest mover among those it can name and did attribute, and is not described as the largest, since the per-branch list already shows every branch’s move.
It reads as words, not internal codes.
Dominant: T_total, 100%now reads the change in the pool total explains 100% of the move, and the other factors as the value coming in, the driver total, the shift in this slice’s share of the pool, and the dimension assignment. A qualification that appeared asoffsetting_negatives_ratio— usually the most important one, the one saying a half-percent headline hides large movements cancelling out — is in words in both the headline and the trace summary. Tables are named as your project knows them rather than as longanalyzetable_identifiers, in knock-on estimates and in the explanations given when an answer declines; where a name genuinely cannot be resolved the answer names the step that produced it, or leaves the reference out and still reads normally. A blank value reads as (no value) or (blank) rather thanNone. An answer can no longer give its own confidence two spellings at once —medium (mostly_clean)in the opening summary and medium (mostly clean) two lines below — and where it declines a whole-pool figure because an earlier allocation narrowed what this one can see, it says what it saw in plain words instead of quoting an internal signal name.The same question returns the same answer. Where two members moved by exactly the same amount their order was left to the warehouse, which promises none — so a repeated question could reorder them, or, on the boundary of how many movers are shown, swap one for the other, along with that member’s own before, after and change, and even which field the answer chose to break the change down by. Equal movers are now ordered by the value they were broken down by, so a difference between two runs is a difference in your data.
Driver what-ifs answer correctly on more models. Asking what a change to a driver would do re-divides the pool under the new weights — but where more than one step writes into the same result table, it re-divided the other steps’ money too, overstating one real model’s $29,000 change as $162,000 with nothing to indicate a problem. Such a result now names every step writing that table and points you at the tool for explaining a change that has already happened, and the check printed alongside says plainly that it confirms the split adds up — not that the amount being split is the right one. A step that carries its driver value through under a different name can be asked about at all now: use the driver table’s own column name, while the members the answer reports are named as the result table spells them. And where the warehouse rejects one of the reads a reslice needs, the answer says which read failed and whether retrying is likely to help, instead of returning an internal error. See Driver What-Ifs.
And a what-if names the same table every time when it points at the biggest single impact. Asking where a change would land returns the outputs it reaches plus a note naming the largest one — and where two came out equal, which one got named depended on the order the allocation steps happened to be stored in, so the same question could answer differently. Two equal outputs is the ordinary case rather than a rare tie: where two allocations draw on the same pool, each hands its output the same share, and a reader told to scrutinise one of them examined one of two identical exposures with nothing on the page to say the other existed. The named table is now stable, and the answer’s underlying data says how many share the top figure.
Cost-tracing can search combinations of dimensions. Where your workspace has explanatory-cut discovery switched on, asking what drove a change now also tests combinations — a move confined to one region and one product line, say — rather than one dimension at a time; previously the combination search never ran at all unless it was requested explicitly, which nothing did. The answer stays conservative: where nothing explains the move on its own, it says so rather than picking something. Both searches remain off by default.
-
Busy workspaces do less work for the same result. A running workflow now asks PlaidCloud for far less of the same information while it works, which frees up capacity where many workflows run at once. And deleting tables, or reading a table’s dependencies, is much faster on a large project: before a table can be deleted PlaidCloud works out which workflow steps use it, and deleting a folder or several selected tables asked that question separately for every table against every step — so a folder of fifty tables on a project with hundreds of steps could sit for the best part of a second before the confirmation appeared. It is now answered for the whole selection in one pass, carrying only what is displayed. Which steps are reported as using a table, and everything you see, are unchanged.
-
Idle Lakehouse warehouses now scale their query capacity down, and back up automatically. A warehouse’s query-execution capacity used to stay at full size around the clock whether or not anyone was running queries against it. PlaidCloud now watches query activity and, after a warehouse sits idle for a while, scales that capacity down to a small floor — releasing infrastructure you weren’t using — then scales it back out as query load returns. The one thing to notice: the first query against a warehouse that’s been idle can take a little longer while capacity comes back online; a warehouse in steady or busy use never sees this. The warehouse itself stays reachable throughout. See Lakehouse Management.
-
The Microsoft 365 Copilot agent installs as “PlaidCloud”, and its sign-in screen is PlaidCloud-branded. The agent every workspace publishes to Microsoft 365 Copilot is now named PlaidCloud in the Teams and Copilot app picker, with the workspace name shown in its description to tell multiple workspaces apart — where it previously took the workspace’s own name, which read as an unfamiliar app rather than PlaidCloud. Its sign-in window now carries PlaidCloud’s branding too, so the screen people complete is recognisably PlaidCloud’s. To pick up the new name, an already-installed agent is re-downloaded from the control plane and re-uploaded once; the branded sign-in applies on its own. See Microsoft 365 Copilot.
-
Sage Intacct steps are grouped under a new External Systems category. The five steps that read and write Sage Intacct — importing balances, AP bills, and ad-hoc queries, and posting journal entries — now sit together under Sage Intacct in the Add Step palette and the step reference, alongside NetSuite and SAP, instead of scattered across the general Import and Export groups. See Sage Intacct Steps.
-
Slack and Teams notifications send again, and REST steps authenticate again. A change that hides connection credentials wherever connections are listed also hid them from the three workflow steps that use them. A Notify Slack or Notify Teams step failed with a complaint that its webhook address was not a web address — the address had been replaced with a placeholder before the step ever saw it — so the message blamed the connection for something that was not wrong with it. Because the step failed rather than merely skipping, the workflow stopped there, and anything after it did not run; where the notification was the last step, as it usually is, the run went red with the work already done. A REST step sent that same placeholder in place of the connection’s API key, bearer token or basic password, so the service it called turned the request away as unauthorized; a connection using OAuth2 failed a step earlier, when the token request itself was rejected. All three steps now read their working credentials from the connection itself rather than from the listing. There is nothing to change on your connections — a step that was failing succeeds on its next run, and a run that stopped at one can be resumed or re-run as it stands. A Slack or Teams step whose connection carries no webhook address for the environment it names now says so, naming both, rather than failing further along. Credentials stay hidden everywhere connections are listed or described, which is what that change was for and is unchanged. See Notify via Slack, Notify via Microsoft Teams and REST Request.
-
A cost-trace answer’s opening line now says what it measured and which population it measured over. That line is the one built to be forwarded on its own, and it was missing both. Where the answer covered a single measure it had no subject at all — “it rose 10.9%” — which is unanswerable to anyone reading it without your question beside it, and a rise in cost does not read as bad news without the noun. Separately, an answer scoped to one member never said so in that line. Asking why commercial net contribution fell returned an opening line asserting the measure was -$15,957,089.93 and worsening, while the same model’s unscoped answer put it at +$24,229,133.70 — so anyone forwarded that line alone was told the business was loss-making. The scope was on the page, three lines down, and simply did not travel with the sentence. It now reads “the total in claims_cost_by_line_region for line=COMMERCIAL_AUTO rose 10.9%”. Two choices are worth knowing. It names the table rather than the value column, because with one measure the column name distinguishes nothing and names like “amount” read as a business measure while naming none — readers shown that version rated it worse than the bare “it”. And the scope sits inside the claim rather than in a trailing sentence, because a line that gets copied out gets truncated, and a scope note at the end is the first thing to go. It applies to every answer that reports a figure — including the one for a period whose net barely moved while large amounts moved up and down inside it, which now names its table too — and deliberately not to an answer that declines to report a figure, where there is no claim for a population to bound. An unscoped answer is unchanged except for gaining the subject, and still does not announce that it is unscoped; that is a separate gap and is being tracked. No figure changes, and the line grows by two to five words. See Analyzing Allocations with AI and Tracing Allocations.
-
A cost-trace answer covering several value columns no longer shows percentages in its per-column breakdown when one of those columns is below zero at both ends of the period, and says which way that balance moved instead. Asking why net contribution moved returned
-$3,040,077.92 (-23.5%)for a column running from -$12.9m to -$16.0m — nine lines under a summary describing that very same movement as grown, and beside two amounts a reader who divides one by the other gets +23.5% from, so anyone who checked the arithmetic concluded the answer was wrong. A year later the same answer showed-7.7%for that column directly beneath three columns whose own-N%meant fell, and got smaller, where it meant the opposite. The root of it is that such a column’s percentage is measured over a negative amount and its neighbours’ over positive ones, so the four do not form one comparable set — and readers shown them ranked the smallest of the four movements as the worst line on the page. Three attempts to fix the single row were each tried and each measured worse than the last: re-labelling its percentage in words left readers reading it as the largest rise, and removing only that row’s percentage left the other three reading as the whole story, giving a confident “nothing here moved more than 9%” against a real 23.5%. So the breakdown now shows the amount and the opening and closing levels for every column and a percentage for none, with the negative column reading-$3,040,077.92, a growing negative balance, from -$12,917,012.01 to -$15,957,089.93. The amounts are directly comparable, correctly ranked, and add up to each other, which is what readers said they would put in front of anyone. A breakdown whose columns all start from positive amounts is untouched and keeps every percentage, as is a column whose balance crosses zero within the period; and the summary line at the top of the answer still gives the percentage, since it states the direction in words first and has no column of other percentages beside it to be compared against. No figure changes, and the answer is slightly shorter than before. See Honest Answers and Tracing Allocations. -
A misspelled parameter in an MCP recipe call is now refused rather than ignored.
mcp_recipe_runtakes aparamsobject, and a key it did not recognise was dropped in silence. For most recipes that meant an option you set simply had no effect; for the allocation cost-trace recipe it changed the question. Asking for a trace filtered to one entity and broken down by account, with either parameter name a single character off, returned a confident whole-pool answer — neither the filter nor the breakdown applied, no error, and nothing in the result to show the answer was not to the question asked. An unrecognised parameter is now rejected with a message listing the ones that recipe accepts, so the name you meant sits beside the one you typed. A misspelled required parameter already failed loudly and is unchanged, as is every call whose parameter names are correct. See Batching Requests. -
A cost-trace answer that declines to attribute a change now says so in the structured result as well as in the writing. Asking why a cost moved on a table an earlier allocation has already drawn from returns a refusal rather than a number, and the written answer is clear about it: it opens with “this can’t be answered as asked”, shows no amount, explains that summing the whole table would count the wrong rows, and tells you to narrow the question to one slice. Alongside that writing every answer returns a structured list of its limits — the list a coding agent or a workflow step reads to decide whether an answer is safe to build on. On a refusal that list came back empty, with only a “low confidence” rating beside it, and a rating is not a limit. Anything reading the structured answer rather than the prose was therefore told there was nothing wrong with it — which is the wrong way round, since that is exactly how an answer is read before its figures are written back into a table. Such an answer now carries a limit of its own, saying that no figure is reported and why, in the same words already shown to the reader, so the two cannot drift apart. The writing gains one sentence: the limits block now opens by saying no figure is reported, where before it opened on the cause and left the consequence to be inferred from a line further up — which matters because that block is the part people lift out and forward on its own, and read alone it looked like a caveat on a number rather than the reason there isn’t one. Nothing else about the answer changes, including its confidence rating and its suggested next step. Answers that did attribute their change are untouched, and so are answers whose limits already reported an earlier step that could not be attributed — that report covers the steps behind the one you asked about, and this one covers the step you asked about, so between them the whole chain is accounted for. No figure changes. See Analyzing Allocations with AI and Tracing Allocations.
-
A cost-trace answer that says a breakdown could not be produced now names the table it means. Asking for a breakdown by a column that does not exist at every step returned a limit reading “
sales_documentis not a column onanalyzetable_e1c77686-1783-4cc4-a897-b77009d975ba” — an internal identifier, in a bullet that had already labelled itself with that same table’s real name, and on the same page as a suggested next step that also used the real name. One answer, one table, two names, and only one of them something you could look up, paste into a search, or take to a colleague. The real name was in fact available at the moment the sentence was written; it was simply not the one the sentence reached for. The limit and the suggested next step now both use it, so the two agree. Where the name genuinely cannot be resolved the sentence says so and identifies the table by its role — the one this step writes — rather than falling back to the identifier, because an internal id is not a name you can act on either. No figure changes. See Analyzing Allocations with AI and Tracing Allocations. -
Pinning a document folder to the Launcher now works on S3 and Wasabi accounts. Right-clicking a folder in the document browser and choosing Pin to Launcher lit the star and saved the pin, but the folder never appeared in the Pinned lane and nothing said why — so the action looked as though it had worked, and the only clue was the absence. Nothing was wrong with the pin: PlaidCloud finds a pinned document again by listing the folder it sits in and matching it there, and on these accounts that listing reported only files. Folders are not stored as objects in those services — a folder is simply the shared start of the paths beneath it — so there was no entry for the pin to match. Those listings now report their folders, worked out from the file paths they already return, so a folder pin is found again however deeply it is nested, and a folder with nothing in it is found too. Folder pins you made before this appear on your next reload — there is nothing to re-pin. Files pinned correctly on every account already, and folder pins on other account types are unchanged. See Pinning (Favorites).
-
Deleting a workflow now deletes its scheduled events. A workflow’s entries in the Event Scheduler survived the workflow itself being deleted, and they did not merely sit there: the timer behind each one kept its schedule and kept starting runs of a workflow that no longer existed. So a workflow you had removed carried on waking up on its old cadence, failing, and doing it again the next night, with the events that caused it no longer reachable from the Event Scheduler to turn off. Both the events and their timers are now removed as part of deleting the workflow. Events scheduled against other workflows are untouched, and deleting a whole project already cleaned up correctly. See Event Scheduler.
-
A project report in PDF format generates again. Choosing PDF returned “There was an unexpected error” and no file, while the interactive HTML version of the same report worked — so the report was available only in a format you may not have wanted, and nothing on screen explained why. The PDF is now assembled and written in one place rather than being handed to a separate worker to finish, which is where it was failing. The report’s contents are unchanged. See Viewing the Project Report.
-
A download that fails now tells you what went wrong. Any download whose file could not be produced — a project report that failed to render, for instance — hit a second failure while recording the first, and that second failure destroyed the response: your browser received a bare server error rather than the message the page expects, and the line meant to record the cause was never written. So the one place the reason would have been kept was the one place it never reached. Both now work, so a failed download explains itself and the next one can be diagnosed.
-
A cost-trace answer that cannot tell you whether its own movement is a large one now says so. Asking why programme margin was eroding returned the fall, the split across cost, revenue and margin, and the members behind it — and nothing at all about whether a fall that size is unusual for that model. Every other answer carries that: a comparison with the same movement a year earlier, and one against recent periods. Neither is produced for a table written by a step that allocates several measures at once, the shape a margin or contribution model takes — each is built for an answer covering a single measure, and picking one of them and reporting it as the answer would be worse than not running them. That decision was recorded only in a diagnostic list the report is not built from, so it reached nobody: the reader saw a step-by-step account and concluded the answer had gone as far as the data allows, when it had stopped short by design. The limits block now says it — naming both missing comparisons, and saying that one step produces every one of the measures, so there is no single-measure answer to ask for instead. It also says plainly that no figure above is withdrawn, because the figures are exact and only the context is absent: read cold, a note under a heading called Honest limits is otherwise taken as doubt about the numbers, and this one is not. Two neighbouring silences of the same kind are closed with it. An answer whose periods cannot be stepped back a year — a fiscal-year label, or a period that is not a date — now says which period formats can be, where it previously filed an internal release marker no reader could act on. And an answer about a table that recombines several allocation branches, whose own combined total could not be read, now says the comparison went with that total rather than mentioning only the total. No figure changes anywhere. See Analyzing Allocations with AI and Tracing Allocations.
-
A cost-trace answer no longer books another step’s movement as a driver effect. Where a result table is written by more than one step, naming the step you want told the answer which step to describe — it did not narrow which rows were measured. The change reported stayed the whole table’s, while the “value coming in” figure beside it covered only the named step’s own pool, and the answer closed the gap by calling the difference an interaction between the value coming in and the driver total. It cannot be one: on these answers the driver total is fixed at zero and so cannot have moved, and an interaction with something that did not move is nothing. What was really in that figure was the other step’s rows. On one department table it came to $2,951,837.58 of a $16,235,106.82 movement — 18%, presented to a reader as a driver-and-volume effect that does not exist — and naming the other step swapped the two figures exactly, so the same movement was reported two different ways depending only on which step you named. The answer now keeps the table’s exact totals and the named step’s own pool figure, withholds the split it cannot make, says the figure covers every step that writes the table, names those steps, and offers a re-run against each — described as a separate measurement of that step’s own pool rather than as that step’s share of the change you are looking at. It applies whether or not the other writer is an allocation: a step that merely appends rows is never offered as a candidate to trace, so it never prompted you to choose, and its movement was folded into the split in complete silence. No total, and no member figure, changes. See Analyzing Allocations with AI and Tracing Allocations.
-
A cost-trace answer no longer warns you about per-factor percentages it never printed. An allocation’s movement splits between a small number of factors — typically the size of the pool and this slice’s share of it — and where those factors moved in step with each other, the answer’s limits block read “the per-factor percentages are not reliable headline figures even though each is individually correct”. There were no per-factor percentages anywhere on the page for the column it was about, so “each is individually correct” reassured you about figures you could not find, and “the per-factor percentages” sent you looking for figures that do not exist. It was not an occasional gap: the answer deliberately withholds that split on exactly the columns this warning covers, so the warning could never sit beside the numbers it described. It now names the one thing that is missing, says which change it is missing for, and names the factors it is about. Naming them is what stops “factors” being read as the answer’s other value columns, or as the members in the table above — and where this warning appears, the members in that table can add up to the figure it is about exactly, so a reader who picks the wrong meaning has the page’s own arithmetic agreeing with them. It also explains a silence you could otherwise only notice by comparing steps, since neighbouring steps do name a leading factor and this one does not — and it says so of that change rather than of the whole answer, because a step further up the chain names its own. Where a neighbouring note already gives a split between those same factors — which happens when the answer covers a whole pool rather than one member — the “no leading factor” half is dropped, because the page has just stated one. It stops short of denying a breakdown outright: other notes on the same figure legitimately give one in different terms, and the table of members printed just above is a breakdown too. It closes by saying what it covers rather than declaring the amount sound — a separate note about unevenly loaded periods can be saying the opposite two lines away. The short form, which appears both beside the figure in the step-by-step account and in the confidence line at the top, and the suggested next step were reworded to match, so every place this note appears says one thing. A neighbouring note was quoting the withheld split too, describing a movement as mostly pass-through by referring to an attribution the answer does not print; it now describes the movement itself. No figure changes. See Tracing Allocations.
-
A cost-trace answer no longer says a breakdown is missing from the answer while printing one, or describes the printed table as something it is not. Asking why one entity’s cost moved, broken down by account and sales document, returned a table headed “Top movers by account, sales_document” and then, further down, “The member breakdown you asked for is not in this answer” — and in the same sentence “so the members you see are grouped only by the rest”, which says the twenty rows above were grouped by account alone. They were not: they are the traced table’s own members, at the full breakdown that was asked for. The note is about a table one step upstream, whose narrower layout does not carry a sales document column and whose members are not listed anywhere — so the sentence pointed at the only table on the page and mislabelled it, and the short form of it read as a flat denial that any breakdown had been given. Both now name the step they are about — “was not available at this stage” — and the explanation describes that step’s own table rather than what you are looking at. The note is not withdrawn: a breakdown that was asked for and could not be produced is exactly what it exists to report. The suggestion under “To go further” said the same thing the other way round — “re-run grouped by a column that exists on the traced table” — about a column that does exist on it and is in the heading of the table above, so following it would have thrown away a breakdown that worked; it now names the step’s own table, like the note. No figure changes. See Tracing Allocations.
-
A what-if answer now warns you when the data it is resting on has not been reloaded recently. Where stale-data flagging is switched on, asking why a cost moved over a pool last loaded 139 days ago returned “input pool data is stale” and dropped its confidence a notch. Asking a what-if about that same pool returned an estimate with nothing attached at all — no warning, no mention of the age. It was missing from the one place it matters most: a what-if propagates a change, or reweights a driver, using the shares your model realised on its last run, so out-of-date data is precisely the case where the estimate is least dependable and was the only case where the answer said nothing. Both what-if answers now name the pool or the driver, how many days ago it was loaded, and the window your administrator set, in the same words the “why did this change” answer uses on the same table — so one pool cannot be reported as two different ages depending on which question you asked. The same gap existed on the direct “why did this change” tool used by coding agents, as distinct from the guided one, and is closed with it. Two limits are worth knowing, and both apply to the “why did this change” answer as well: the age is asked only of tables loaded straight into PlaidCloud, because a table a workflow step builds can report only when that step last ran, which is a different question; and where more than one table of the same kind is stale, the oldest of each kind is the one named. Neither ever reports a stale table as fresh. Nothing changes on a workspace that has not switched stale-data flagging on, and no figure changes anywhere. See Analyzing Allocations with AI and Tracing Allocations.
-
A cost-trace answer’s member table now says which figures it is showing when they are not the ones the answer is about. Asking why margin fell returned one table of members headed “All movers by program — cost”, topped by a programme at -$40,680,000.00 — against a margin movement of $10,701,036.06. Four characters of heading separated a cost figure from a margin question, so a reader scanning for “which programme caused this” walked away with a number four times the whole movement. The answer did warn about the mismatch, but only about a breakdown you had not asked for yet; the table actually printed carried nothing, and the printed table is the part that gets copied into a slide. It now reads “These are cost figures. The answer leads on margin, where the biggest mover is not necessarily the one at the top here.”, placed above the rows so it travels with them. The wording states what the figures are before it says the order can differ, because knowing the ranking might differ does not stop you reading the top row as the cause. Only answers that picked their own breakdown are affected — where you name the breakdown, every column gets its own table and the two always agree. No figure changes. See Analyzing Allocations with AI.
-
A cost-trace answer that chose its own breakdown no longer says no breakdown was given, a few lines above the breakdown it printed. Asking why a cost moved without naming a field to break it down by returned “candidate dimensions searched — no breakdown was given” on the line summarising the answer’s confidence — four to eight lines above a table headed “All movers by account”. The fuller note further down was right, and right because of one word: “No breakdown dimension was given, so 3 candidate dimensions were searched” is a statement about the request, and the shortened version dropped the word that made it one. What survived contradicts the table underneath it, in the sentence a reader skims in full, and the natural way to resolve that contradiction — “I must have asked for this breakdown after all” — is wrong, and changes how the percentage beside it should be read. One automotive answer carried both wordings at once: the correct one where it lists its limits, the contradiction in its trace, and the table between them. The short version now reads “no breakdown dimension was given”, matching the fuller note word for word so the two cannot drift apart again. An answer that genuinely prints no breakdown still says a search happened, because that is the honest case and it is the one where a reader most needs to know the field was chosen rather than asked for. No figure changes anywhere. See Analyzing Allocations with AI.
-
A cost-trace answer’s per-branch and per-column figures now say when they carry a caveat. The block listing each branch’s change is the part of an answer that gets lifted into a slide, and it was the one place a caveat could not reach: a line is marked only when it is less certain than the answer as a whole, so when every branch shared the same problem none of them was marked. Four confident amounts travelled with nothing attached — under an answer whose own note said the whole movement was what a half-loaded period would produce — while the milder case, one weak branch of two, was marked. Disclosure was inversely proportional to how widespread the problem was. Each affected figure now carries “carries a caveat”, and where every figure in the block is covered by the same one, the block says so once and says that the caveat bears on comparing the figures with one another: a shared doubt read as four separate ones leads a reader to discount the amounts and keep the ranking, which is precisely the part a half-loaded period would leave standing. Two answers covering several value columns gain the same mark on the one column that carries a caveat among clean siblings — in one case the column its headline is built on, which until now was the only one on the page with nothing against it. Figures that are not caveated are untouched, and no figure changes. See Analyzing Allocations with AI.
-
A cost-trace answer now names the two periods it compares, and only calls a comparison year-on-year when it is one. Not one answer named a date, a quarter or a year anywhere, while several asserted a relationship between two periods — “62% the size of last year’s move; last year moved +$6,183,330.15”. So a figure quoted to the cent could be tied to no filing, no trial balance and no prior-year record, and two answers about consecutive spans were indistinguishable from two about the same span: one tax answer ends at $25,999,193.60 and the next one starts there, with nothing on either page saying why. It reads worst on a model spanning jurisdictions, where four entities are named and every figure is in bare currency units — a “year-on-year” label over what might be sequential quarters is the kind of mislabel an auditor challenges first. Every answer now carries “Periods compared: year 2024 → 2025” in its opening paragraph, ordered to match the “from $X to $Y” pair beside it so each figure attaches to a period. The year-on-year label is claimed only where the two periods really are a year apart; a comparison of consecutive months or quarters reads “against a year earlier” and names the window instead, since it is measured against the same window a year before but does not itself span a year. The amount it compares against names its own years too — “2024 → 2025 moved +$6,183,330.15” — so the figure the percentage divides by can be traced rather than taken on the words “last year”. Currency is a separate question and is deliberately not addressed: PlaidCloud reports the amounts your model holds and does not know their currency. No figure changes. See Analyzing Allocations with AI.
-
A cost-trace answer that warns a movement may be an artefact of a half-loaded period no longer clears itself one line later. Four answers about one entity’s cost carried that warning and, three lines above it, “YoY: normal — 89% the size of last year’s move” — which reads as a second opinion agreeing the movement is routine. It is not a second opinion: that verdict is a ratio whose top half is the movement being doubted, so a period that has not finished loading pulls it toward “normal” for exactly the reason the answer is warning about. A reader files it as “large move, but normal year-on-year” and never checks the load, which is the one action all four answers ask for. The verdict now says what it rests on — “this verdict is computed from the change reported in this answer, so it is not an independent check on whether that change is real” — and where the two periods moved opposite ways, that now leads the sentence rather than sitting five clauses behind the reassuring word: “normal in size, opposite in direction”. The verdict itself is a real measurement and is not withheld, and answers over evenly loaded periods are unchanged. See Analyzing Allocations with AI.
-
A cost-trace answer that cannot answer the question now suggests a next step about the thing it could not answer. Where the trace stopped — a missing allocated column, an input pool that has not been built — the answer said so and then, in the same breath, told you to do something about a completely different table: “this can’t be answered as asked — the expected allocated column is not on the result table. Trace cost_pool as the target in its own right.” Both halves were true and the second had nothing to do with the first, because the suggestion was picked from everything the agent had noticed anywhere along the chain rather than from the step that actually stopped. A reader who followed it spent the next query in the wrong place and came back no wiser. The suggestion now comes from the step that stopped, falling back to that step’s own written guidance — so a missing allocated column tells you to check the table’s columns, and an unbuilt input pool tells you to run the workflow that builds it. Where there is genuinely nothing specific to offer, the answer still passes on the nearest useful suggestion rather than leaving you with none, but now says plainly that it is about a different step. Answers that could be attributed are unchanged, and no figure moves. See Analyzing Allocations with AI.
-
A cost-trace answer that declines to run no longer explains itself in PlaidCloud’s internal vocabulary. Asking about a table without naming its period column, where the column could not be worked out automatically, returned “auto-detect returned ‘no_candidates’” — an internal code, quoted as though it meant something to the reader, on what is an entirely ordinary request. The same code appeared with no explanation at all in the what-if tool, and the note explaining why a year-on-year comparison had been skipped named the status of the skip, plus — for every cause but one — a second code inside the reason given for it. Each now says what happened in plain words: “No period column was supplied and none of the table’s columns look like a period column. Pass temporal_filter.column explicitly” — and where more than one column looked equally likely, it lists them, so the answer contains the fix. Nothing about which requests succeed or fail changes; only what an unsuccessful one tells you. See Analyzing Allocations with AI.
-
A cost-trace answer that explains a movement by a member’s shift in share of the pool now shows the two shares it shifted between. Answers said, in several places, what the figure was not — “that is its shift in share of the pool, not its own change” — and never once what it was: no before-and-after share appeared anywhere, so nothing connected “its share moved” to “71% of that column’s change”. Those are different things and only the second was ever given. It mattered most where the two came out close: on an insurance model the figure quoted was 11.7 times the movement and the member’s own change was 12.3 times it — five percent apart, and inches apart on the page — which teaches you that the sentence separating them is pedantry; and then on an automotive model the same two figures are 71% and 98%, where the answer offered nothing on which of them belongs in a board pack. Each such line now carries the pair: “by its shift in share of the pool, from 26.5% to 18.2%”. The version of the line that prints no percentage at all — used where a member’s shift is larger than the whole movement, and a figure over 100% would be absurd to publish — gains it too, and is where it helps most, since until now that sentence carried no number whatsoever. Where the pool is positive at one end of the comparison and negative at the other, the two figures are not shares of anything and are left out rather than printed. No existing figure changes. See Analyzing Allocations with AI.
-
A cost-trace answer that tells you its best candidate fell short now says what it fell short of. Asking why a bank’s net margin moved, without naming a breakdown, returned “branch … accounts for a share shift worth ~45% of that column’s change, below the bar for a finding” — so you learned a figure had failed a test and never learned the test, and could not tell a near miss from nowhere close. That is the whole judgement the sentence invites, on the one kind of answer that exists because the finding is uncertain. The threshold could not simply be written into the wording: it rises with how many breakdowns were examined, from 60% up to 80%, so it is now carried with the answer and quoted from there — “below the 60% a finding needs”, and a higher figure on an answer that searched more dimensions. Where the candidate’s figure is larger than the whole movement it is written as a multiple rather than a percentage, and no threshold is quoted there, since a percentage bar beside “11.7×” would argue with itself. See Analyzing Allocations with AI.
-
A cost-trace answer about a table that recombines several allocation branches no longer numbers those branches as if each fed the next. The step-by-step account at the end of an answer numbered every entry “Stage N”, and that numbering meant two different things depending on the model. Where the agent had followed a chain, “Stage 2” fed “Stage 1” — a real hop upstream. Where the answer covered four branches recombined into one table, “Stage 1” to “Stage 4” were four branches side by side that never touch each other — so anyone who had read the first kind of answer took the second for a four-hop chain and drew a lineage that does not exist, concluding one branch sat four allocation hops above another. One answer used both words for the same two tables six lines apart, calling them “Branches 1, 2” where it listed its limits and “Stage 1, Stage 2” in its trace. A parallel branch now reads “Branch 2 of 4”, numbered the same way the rest of the answer already numbers it, and “Stage” appears only where one step genuinely feeds another. A branch covering several value columns keeps one number, its lines told apart by the column each names, and a table that recombines just one branch reads “Branch 1” with no count after it. Answers that trace a chain read exactly as before, and no figure changes anywhere. See Analyzing Allocations with AI.
-
Deleting a folder of dimensions no longer reports a failure once the folder holds more than about fifteen. The dimensions in a folder were deleted strictly one after another, so how long it took grew with how many there were, and a folder of around sixteen crossed the twenty seconds at which the screen stops waiting and shows an error. The delete had in fact worked, and carried on running after the error appeared — so the folder you had just been told had failed to delete was gone when you looked again, with nothing on screen to say which of the two had happened. A folder’s contents are now deleted several at a time, which brings a folder of that size comfortably inside the limit; the more it holds, the bigger the difference. Deleting a folder of tables has had the same change, having escaped the problem so far only by being quicker per table, as has the action that clears out tables no longer referenced by any step — that one covers a whole project rather than a single folder, so on a large project it had the furthest to fall behind. Several at a time rather than all at once is deliberate: everything in a project shares one index of what lives in which folder, and emptying a large folder all at once would contend on it. A delete that fails partway through still leaves the folder itself in place, as before.
-
A cost-trace answer about a figure that is negative at both ends no longer describes a deepening loss with a word that reads as an improvement. Asking why a line of business moved returned “net_contribution fell 23.5%, from -$12,917,012.01 to -$15,957,089.93” — a loss three million dollars bigger, announced with the one word a reader scanning a loss line takes to mean it got smaller. “Fell” is correct about the signed figure and backwards about the quantity most people have in mind, and this is the sentence that gets pasted into an email, so everything careful further down was being read against an opening line already taken the wrong way round. Where a figure is below zero at both ends the answer now describes the size of the balance instead — “went further below zero — the negative balance grew 23.5%” — with the same two figures after it, and the mirror case reads “moved back toward zero — the negative balance shrank”. No figure changes: on such a pair the percentage already shown is exactly the amount the balance grew by. The answer still does not say whether that is good or bad, because which way is good depends on the column. Figures that cross zero, and the ordinary case of a positive figure, are unchanged. See Analyzing Allocations with AI.
-
A cost-trace answer that traces a change back through several allocations now says which rows each step’s figures cover, and which step each share is a share of. Asking why one entity’s admin cost fell listed two steps under one heading: the entity’s own slice at the first, the whole department pool at the second, with nothing on the page marking the difference. Dividing one by the other gives an inviting 57% — which compares a filtered figure with an unfiltered one and is a share of nothing, and reads exactly like an allocation share, so the wrong answer is self-consistent and nothing corrects it. Each step now states its population, on the same axis and only where the steps disagree: the sliced one reads
(entity=DE)and the one above it(all entity values), with the opening line carrying(slice: entity=DE)as before. Marking only one of them would read as an extra fact about that step rather than as a contrast, so both are marked or neither is. The same two steps also each reported “account=600000 = 64% of the delta” — identical wording against changes $6.9m apart, so they read as one finding restated when they are two findings that happen to agree; each now says which step its share is of. And a note explaining the split as “~100% to the value coming in and ~0 to the driver total” said so as a fixed phrase, above that same step’s own measured 82%. Only the driver half is forced by the arithmetic — a driver divides the pool and cannot change its size — so that half is now stated as~0%and the rest is described as splitting between the value coming in and the interaction between them, rather than claimed for the value coming in. No figure anywhere changes (sc-25342) (@simozzy). See Analyzing Allocations with AI. -
A cost-trace answer that warns its total hides large offsetting movements now says by how much. The warning stated the test it applies — the biggest single movement inside the change being at least a quarter larger than the change itself — and stopped there, so an answer where that movement was twelve times the change read exactly like one where it was one and a half. On an insurance model the warning was attached to a $1,792,719.72 net change whose largest line had moved $22,067,919.71: a reader who took the stated rule as the finding and stopped came away with roughly $2.2m of hidden movement where the answer’s own table showed $22m. The sentence that exists to warn you the headline understates was itself understating, by an order of magnitude. It now names the member and the two figures — “Here account=LAE moved +$22,067,919.71, larger in size than the whole net change of +$1,792,719.72” — both signed, so a line that fell inside a total that rose reads as the offsetting movement it is, and both already printed elsewhere in the answer so you can check them. The stated rule stays exactly as it was. Where what tripped the warning was not a single member’s own movement, the sentence names the measure that did and quotes no figure. No confidence rating, and no other figure, changes (sc-25341) (@simozzy). See Analyzing Allocations with AI.
-
A cost-trace answer that warns its total hides large offsetting movements now states the test it actually applied. It explained itself with “the top mover alone exceeds the net delta” — a looser rule than the one the agent uses, which is whether the biggest single movement inside the change is at least a quarter larger than the change itself. A reader who took the stated rule at face value and checked it on the next answer found it apparently broken: an insurance model whose largest line moved $24,124,561.91 against a net of $23,755,719.72 — a 1.6% overshoot, correctly rated “high (clean attribution)” with no warning, because that is a mild and arithmetically ordinary overshoot rather than the ninefold churn the warning exists for. The wording now names the threshold and every measure it can be applied to — one member’s movement, that member’s shift in share of the pool, or one factor’s contribution — so the rule an answer states and the rule it applies are the same rule and can be checked against each other. No confidence rating, and no figure, changes. See Analyzing Allocations with AI.
-
Converting a large Alteryx workflow no longer holds up everyone else on the same server. Reading the file and working out what each Alteryx tool becomes is the slow part of an import, and it ran where nothing else could proceed until it finished — measured at four seconds on a 2,000-tool workflow, during which everyone else’s screens simply waited, with nothing to indicate that somebody’s import was the reason. That work now happens alongside normal traffic: the longest anyone else waits is around a twenty-fifth of a second, whatever the size of the workflow being converted. The conversion itself takes somewhat longer in exchange, and what it produces is unchanged. Note that conversion time is driven by how complex your formulas are rather than by the tool count alone — a workflow of simple tools converts far faster than the same number of tools carrying nested conditional expressions. See Migrate Alteryx Workflows.
-
A connection that signs in with OAuth2 can no longer hold up everyone else while it waits. Before PlaidCloud calls a REST connection’s API it fetches an access token from the address that connection names, and that fetch ran on the same thread serving every other request, with no time limit on it. So a token address that accepted the connection and then never replied could leave the whole workspace unresponsive for as long as it stayed silent — with nothing on screen to point at a connection as the cause, since the connection’s own step was one of the many things left waiting. The fetch now runs alongside other work and gives up after 30 seconds, failing that one call and leaving everything else running. This covers REST and Mulesoft connections, Salesforce and Sage, and connections imported from Postman. Nothing changes for a token address that answers normally. See Create a Connection.
-
A forward-looking allocation answer no longer marks a figure unreliable because of rounding. Where a change passes straight through from one table to the next, the amount arriving is the amount leaving — but the two totals are added up in a different order, so they can differ in the last decimal place, by roughly a billionth of a penny on seven million. The check for “this target holds more than the pool it came from”, there to catch a genuinely shared or rescaled target, was treating that as a real overshoot: one pass-through was marked unreliable while an identical one beside it was not, because the rounding fell the other way. Nothing in the written answer was affected — the mark appears in an answer’s underlying data, which is what a dashboard, an export or a connected assistant reads.
-
A step whose run was interrupted now reports itself as abandoned, instead of appearing to run forever. When the work behind a step went away mid-run — because someone pressed Stop, or because platform maintenance interrupted it — nothing ever corrected the step’s status. The workflow view kept showing it as running with a duration climbing indefinitely, which reads as an extremely slow step: in the case that prompted this, a step that takes three seconds displayed as running for over twenty minutes. Such a step is now marked abandoned, with an explanation in its status tooltip, and its duration stops; an open workflow view refreshes on its own. An abandoned step did not complete and produced no output — it is not a slow step and not a data problem. Either Resume the run, which runs the abandoned step again, or re-run the whole workflow. See Follow a Step’s Status.
-
A screen left open for a while no longer stops working until you reload. Signing in gives your browser a short-lived pass, which PlaidCloud renews for you in the background. The older screens — the project list, the workflow list — renewed it; the newer ones could not, and could only accept or refuse a pass. So once it expired, those screens answered every request with “not authorised” however many times you retried, until you happened to visit one of the older screens or reloaded — at which point the newer screens started working again, having been put right by something you did elsewhere. Every screen now renews the pass the same way, so the wait is a moment rather than a dead end, and recovery no longer depends on which screens you visit or in what order. Two smaller things come with it: while a renewal is under way PlaidCloud asks whoever arrives next to try again, and every screen now does so by itself instead of showing a failure; and if your session really has ended you are taken to the sign-in page and returned to where you were. The in-app Help and support-ticket screens are fixed with them. What each screen is allowed to do is unchanged.
-
A workflow step saved with an output column that has no data type now saves, and runs. Adding an output column by hand used to leave it without a type, so saving a Table Lookup or any of the Inner, Outer, Anti and Cross Join steps failed with Update Failed – Internal Server Error and removing the column again was the only way out. A new row now starts as Text, and you can change the type as usual.
A step already saved that way also failed when it ran, because it could not build its output table. The type is now worked out as the step starts, from the source column that output column reads; where there is nothing to read it from the column is treated as text — an Extract SQL step’s columns come from the query you wrote, and where several sources carry that column name under types that disagree, text is used rather than guessing one of them, since a wrong guess produces a conversion the warehouse can reject. This reaches every step that builds its output table from configured columns: Table Lookup, all four Joins, both Unions, the Extracts, Append, Upsert, the two geospatial steps and the file imports. Multi-Table Join is the deliberate exception — it stops and names the column, which is more useful than a guess in a step joining several tables. Setting the column’s Type in the step form remains how you say what the column should actually be; it is no longer what stands between the step and running. See Column Data Type.
Two related cases go with it. Creating a table with a column left without a data type no longer fails outright — the column is created as text, covering tables built through the API and through the AI assistant. And a step whose row condition compares an untyped column now runs: steps that delete, update or reshape rows in place send their row condition to the engine separately, and a recent security change to how that condition is read turned away any comparison involving something the platform had no type for — an untyped column, hand-written SQL used as a column, or the result of a user-defined function — stopping the step with an internal error about a refused query that named nothing you could act on — and it applied to every comparison those can appear in, not only a check for empty. A column given the interval type was refused the same way with nothing untyped in the condition at all. All of these run again, conditions that ran before are unaffected, and the query forms that security change exists to refuse are still refused.
-
Excel imports no longer alter the values they bring in. A code held as a number in the spreadsheet — an account or a product id — arrived in a text column with
.0on the end, so600100came in as600100.0; only the rows actually holding a number were affected, which is why a column mixing numeric codes with lettered ones came in half-changed. Three smaller versions of the same fault went with it: a very large whole number arrived in scientific notation rather than as its digits, a date lost its time part, and a duration was written in a form that changed shape once it passed a day. Separately, a spreadsheet that records its true/false columns as1and0imports again — such a file used to stop the whole import with an error naming the column — not merely the rows concerned, and not only the flag column. All of these read as they did before July’s change to the way spreadsheets are read; columns imported as a number or a date were never affected. Re-run the import to correct rows already loaded. See Import Excel. -
Timestamp columns no longer import as empty on Lakehouse v2. Importing a CSV or other delimited text file into a Lakehouse v2 workspace left every timestamp column empty while the import reported success, so nothing pointed at the problem until a later step or a dashboard turned up missing dates. The date format PlaidCloud handed the warehouse was written in the wrong dialect’s format codes, and the two disagree on the most common one in a timestamp: the code sent for minutes means full month name to Lakehouse v2, so asked to read
22as a month name the warehouse matched nothing and returned an empty value for every row rather than an error.The same misreading applied to
to_timestamp,to_dateandto_charanywhere they appear — a transform expression, a view, or a converted Alteryx workflow — where instead of emptying a column it produced visibly wrong text: aHH24:MI:SSformat rendered14:22:31as14:August:31. This affected any workspace on Lakehouse v2. Parquet imports were never affected, because they carry their own column types and never build a date format, and no other warehouse type was affected. Already-imported rows are not corrected retroactively — check any table you loaded from text files with dates or timestamps, and re-run those imports.If you imported a file after this fix was first announced and still found empty timestamps, that is why. The correction reached the main service but not the separate, slimmer service that builds most file imports, which was running an older version of the shared code. Both now carry it. Re-run any import you ran in between and check its timestamp columns. One related case is not fixed: a column whose data type is Time still imports as empty on Lakehouse v2, for a different reason — the warehouse function used to parse it cannot produce a bare time-of-day value at all. Import the column as Timestamp or as Text until that is addressed. See Import CSV.
-
Exporting a project archive no longer freezes the window, hides a table it could not read, or reports a failure as a success. Choosing Export Project Archive used to hold the window on a loading spinner for the whole archive, with no progress and no way to cancel or step away, and it gave up with an error after ten minutes even though the archive usually carried on running — well inside how long a real archive takes, since on the workspace this was reported from archives of 42, 45, 54 and 64 minutes all occurred against 15 seconds to 7 minutes for a typical one. The window now closes as soon as the request is accepted, a progress window follows the archive, and a notification reports the result. Scheduled archives are unchanged.
What that notification says is now true in two more cases. A table listed in the project with no data behind it no longer disappears quietly: the archive is still written, that table’s data is left out, and the export names the tables it skipped — as does restoring it, rather than presenting them as complete. And an export that genuinely failed used to report as finished with no file behind it, so the problem surfaced later, usually when someone came to restore the archive; a failure is now reported as a failure. This covers every export type, not only project archives, and the export window names the project it is archiving. See Archive a Project.
-
Importing a project archive with Create new copy of duplicate items now produces items you can tell apart. A project variable is identified by its name, so an incoming variable the target project already defined was given a fresh identifier — arriving as a variable named something like
f47ac10b-58cc-4372-a567-0e02b2c3d479, which nothing referenced, while every{variable}in the imported steps went on resolving to the target project’s own value. Nothing failed and nothing said so; the import simply appeared not to have taken. A variable the target already defines is now left alone, and the import tells you which ones it kept.Everything else an archive carries — workflows, steps, tables, dimensions, data editors, views and user-defined functions — got its fresh identifier but kept its original name, so you were left with two workflows called Load Data and two dimensions called Period, indistinguishable in every picker, with anything that looks an object up by name choosing between them arbitrarily. A copy is now named the way a duplicated workflow already is, with
copyappended and a counter if that is taken. This applies where the incoming object collides with one already in the project; two objects that merely share a name are unaffected. See Duplicate Items. -
Where Used on a connection now finds REST v2 steps. Before you edit or delete a connection, Where Used… lists the workflow steps that reference it. A REST v2 step was missing from that list — it picks a connection the same way every other step does, but was never among the step types the search looked at. The risk was in what the list did not say: a connection used only by REST v2 steps looked unused, and deleting it on that basis broke steps the list had just told you were not there. See Clone, Delete, and Trace Usage.
-
A Table Anti Join no longer turns a text column into numbers. The step now offers only source A columns as output, matching what an anti-join returns — the rows of source A with no match in source B. Before, when a join key existed on both sides it could be picked up from source B, and if source B typed that column as a number the output column came out numeric even though source A held text. Source B still supplies the join keys; it just no longer offers output columns, and any that were set are dropped when you open the step. The step’s help note also spells out that it is a left-excluding join — for a left join, use Table Outer Join with its Join Type set to Left. See Table Anti Join.
-
A Macro Concurrent step no longer waits forever on a child invocation that has stopped responding. A child reports its own result when it finishes, so a child whose machine stopped without warning never reported anything — and the step went on waiting. There was no error and no progress to see: one run sat at
Completed 0 of 29 loopsfor eighteen minutes, with nothing to do but stop it by hand. The step now checks that each child it is waiting on is still alive and gives up on one that is not, stopping it, cleaning up after it, and failing at the end naming that invocation, the last state it reported, and when. The other children are unaffected — they finish and their output tables are written as normal. A child working through a single long-running step is left alone for as long as it takes, and a check that cannot be answered is not treated as an answer. See When a Child Invocation Stops Responding. -
An ML: Train Model step can now save a large model. A random forest left at its default hundred trees could not be saved at all: training succeeded, and the step then spent close to four minutes writing the model away before the warehouse connection dropped, reporting
Broken pipeorLost connection— which says nothing about what went wrong and does not tell you the training had worked. Models are now compressed before they are stored, and one too large for a single value is split across as many rows as it needs. A model still too large — more than 128 MB compressed, around twice what a default hundred-tree forest produces — stops as soon as training finishes and tells you its size and the limit, instead of running for minutes and failing with a connection error.Two things to know if you read a model table directly rather than passing it to an ML: Score step: it may now hold more than one row, so read
metrics_jsonfrom a single row (WHERE chunk_index = 0), and the stored model is compressed, so reassembling it yourself means joining the pieces inchunk_indexorder and decompressing before you unpickle. ML: Score handles all of this and stops with an error if any piece is missing rather than scoring with an incomplete model. Models trained before this release are still read as they were. See How the Model Is Stored. -
A report text block now prints the value of a column its text names, instead of printing the reference itself. Text referring to a column was written into the report with the reference still in it, so the finished PDF read
[Year:A] © Mapboxwhere it should have read2026 © Mapbox. The step reported success and the document looked normal, so there was nothing to notice until someone read the page. Naming a column the text cannot read now stops the step and says which column. Ordinary bracketed prose is untouched: a time like[12:30]and an aside like[Note: continued]still print as written. Re-run a report to correct it. See Report Text. -
A table whose column information could not be read no longer looks like a table with no columns. Steps treated a failed read as “this table has none” and said so, pointing you at your own step order and at whether an upstream step had populated the table, when the real problem was the read. Those steps now say the column information could not be read, and why. This covers converted Alteryx steps and ordinary Union steps alike; a Union over a genuinely empty source is unchanged. Two report cases were affected quietly and are worth checking: a report snippet whose source could not be read was skipped, and a report table section came out empty — both on runs that reported success, so the report simply arrived with a piece missing. A report that used to come out missing a section may now stop with an explanation instead. See Reports in a Converted Workflow.
-
Alteryx imports close on their own when they succeed, and stop looking like a warning when nothing is wrong. A successful import used to wait for you to click Close by hand; it now closes itself and opens the generated workflow, with anything worth a second look surfacing afterward as a toast instead of holding up the import. The dialog still stays open when a tool did not convert, so you see what needs attention before you run the workflow. Separately, an imported note or comment now renders in a neutral gray rather than the amber/orange it showed against the dark canvas — a color that read as a warning on an ordinary comment carried straight over from Alteryx. See Import a Workflow.
-
An Access import that cannot read a table now fails and says which one. Importing a Microsoft Access
.mdbor.accdbfile whose tables could not be read finished green, leaving a table with no columns and no rows behind it — and nothing surfaced until a later step tried to read that table and failed, pointing the investigation at the wrong place entirely. The import now fails at the import, naming the file and the table. A file whose tables are genuinely empty still imports, and reports that it loaded no records. See Import Access. -
A member you disabled can be enabled again. Disabling a member from Identity → Members recorded the time in a format the rest of the platform could not read back, and the only screen that can re-enable someone reads it first — so Enable failed with an internal error and there was no way to reverse a disable. The same unreadable value broke the member list itself: with one member disabled this way, Identity → Members and the member pickers that use it stopped loading for everyone in the workspace. Both work again, and members already disabled this way can be enabled normally — nothing needs to be re-done to them, and no data was lost.
-
The dimension-member picker now opens reliably and applies to the right rows. Double-clicking a property cell configured to pick a member from a dimension — in the dimension hierarchy grid or a Data Editor grid — needed a second double-click to open when the cell already had a value, and that second click could land the pick on the wrong row further down the grid. Picking a member in an empty cell and clicking Apply silently discarded it, in some cases Apply cleared the value instead of setting it, and in a Data Editor grid a pick was discarded outright. The picker now opens on the first double-click, and Apply and Clear both work on the row you actually edited, in both grids. With several rows selected, Apply still applies to every selected row — that’s intentional multi-row editing, and it now always includes the row you double-clicked. Separately, a property’s Allow Multiple Selections checkbox, in its Dimension Configuration, can now be turned off; it previously reverted to checked no matter what you saved. See Dimension-Type Properties and the Member Picker.
-
A workspace no longer becomes slow to respond because of requests whose contents never arrived. Where a request reached PlaidCloud announcing itself but its contents did not follow, the platform went on waiting for as long as twenty minutes even though your browser had given up after twenty seconds. Each one held a slot on the process serving the whole workspace, so enough of them accumulating made everything slow, and only restarting the workspace cleared them. Such a request is now given up on after fifteen seconds. Nothing you do legitimately takes that long to send, and file uploads, which genuinely are large, are handled separately.
-
AI agents can now build the text, document, spatial and report steps from their documented shape. Asked to create a Text Sentiment, Topic Model, Word Cloud, PDF text, image OCR, Fuzzy Match, XML or JSON parse, any of the spatial or geospatial steps, or any of the report pieces, an agent read the platform’s own description of the step and built it exactly as described — and the step failed on its first run every time, because the description named the input-column list differently from the way the step reads it. Thirty-six step types were affected; the description now matches. Steps converted from Alteryx were never affected.
-
An AI assistant can now set a step’s run conditions. Asking one to add a condition — run this step only when the source table has rows, or only when a project variable holds a particular value — reported success and stored nothing, so the step went on running unconditionally with nothing to say a condition had been dropped. Checking the change before writing it reported no problem either, and both creating a step and editing an existing one were affected. Conditions set this way are now stored and evaluated exactly as ones you set on the Conditions tab, and the same fix covers a step’s lock, its visibility in the Manager and Explorer views, its retry settings, and the step it goes to on error.
The condition list is replaced in full on every write, so an assistant changing one condition has to send every other condition you want to keep. A condition that could not be evaluated is now refused rather than stored — such a condition used to save and then skip the step on every run — while one that is merely incomplete is reported back as a warning and still written. Check Financial Close Workday is the one condition type an assistant cannot set usefully yet: it can write the condition, but that check never matches, so the assistant warns you rather than leaving you to discover it on the next run. Set that one on the Conditions tab yourself. See Setting Conditions With an AI Assistant.
-
The AI assistant draws diagrams as pictures, won’t invent the numbers in them, and can send email and SMS again. A requested diagram occasionally arrived as a block of diagram source code instead of an image; it now renders whichever notation the assistant picks. A chart or Sankey needs a figure for every bar or band, and where the assistant hasn’t been given one it now asks you rather than drawing a plausible-looking value, so a picture that reads as authoritative is not quietly made up. Separately, asking it to send a message either failed outright or reported success while sending nothing; sending now works, and leaving the recipient out is reported as an error instead of quietly doing nothing. See Using the AI Assistant and Using Email.
-
Two fixes for connected agents reading your workspace. An agent asking “has this changed since I last looked?” was compared only on the identifiers in the list, so renaming or editing a record — without adding or removing one — still came back as “not modified” and the agent could go on working from a stale copy; it now compares the records themselves, consistently whichever server handled the request. And searching warehouses by name returns the matching warehouses: the search answered with a bare identifier instead of records, so an agent got neither the details nor a count and an empty result was indistinguishable from an error. It now returns records like every other search, and matches on any part of the name regardless of case.
-
The Text Sentiment step’s sentence-level scoring is documented. Find sentiment at sentence level — which scores each sentence in a record and returns the average, rather than scoring the whole body at once — has worked all along, but nothing described it. It is documented now, including the case that makes it look like it does nothing: on records holding a single sentence, the average over sentences is the whole-body score, so the two settings agree. See Text Sentiment.
-
The Import Table Bundle and Export Table Bundle progress windows no longer show
<Information Message>above the progress bar. A dialog with no message to display was falling back to a placeholder meant for development, and rendering it as literal text. Dialogs with nothing to say now show nothing there. -
Uploading a document over a connected AI agent works again. An agent that tried to upload a file to your document storage failed on anything larger than a few characters, reporting that the request “could not be parsed as JSON” — so no real file could be sent this way. The upload tool now accepts the file content correctly, and documents of any size go through.
-
Saving rows into a table through the JSON-RPC API works again. The JSON-RPC method that writes a set of rows into an analyze table had been failing on every call since a database-library upgrade earlier in the year — a programmatic client that called it received an error and no rows were written. It now completes and saves the rows as before. The matching REST endpoint is affected by a separate, unrelated issue and is being fixed on its own.
Security
Section titled “Security”-
Editing a security group’s permissions no longer removes the permissions you don’t hold yourself, and can’t grant ones you do not have. Anyone who was not a workspace administrator silently stripped every permission on that group they could not grant themselves — just by opening the permission matrix and saving it, even without changing anything. Workspace administrators were unaffected, which is why this looked like permissions disappearing at random for some people and never for others, and why a permission held by only a few, such as Panel app management, would drop off repeatedly and have to be re-added. Those permissions are now left untouched. Review any security group a non-administrator has edited and confirm its permissions are what you expect — a permission removed this way was removed for everyone in the group.
The matrix only ever offered the permissions you are allowed to control, but a request naming others was accepted anyway, so someone able to manage users could grant a group — and through it themselves — broader access than they held; permissions being granted are now checked against your own. Saving a member or group assignment form with nothing selected now says nothing changed, rather than reporting success while making no change, or, on the member form, removing every group that member had. And permission and membership changes are recorded in the security log: changing a group’s permissions or members, or a member’s groups, previously left no record unless the Git server sync failed, so a permission that changed could not be attributed to anyone afterwards. Every change is now logged with what was granted and what was revoked. See Managing Security Groups and Assignments and Performing a Security Audit.
-
Importing an archive into an existing project keeps that project’s access restrictions, and checks that you can write to it. A project restricted to named users or to security groups was being switched to open access as a side effect of the import, which made it readable — as an Architect — by everyone in the workspace. The restriction was reset because an archive is imported the way a new project is created from one, and a new project is deliberately opened up, since the access lists inside an archive name people from wherever it was exported. That reasoning does not hold for a project that already exists and already has a working access list, so its access type, its lists and its row-access grants are now left exactly as they were. Worth checking: if you have imported an archive into a restricted project, confirm its access setting on the project’s configuration screen.
The import also checked that you were entitled to import something, but never that you had any role on the project you were importing into — so anyone able to import could write an archive’s contents into any project in the workspace, including one they had no access to and one locked to prevent changes. The target project is now checked the way every other change to a project is. See Importing Into an Existing Project.
-
A project archive no longer includes table data for someone who cannot read the project’s tables. Reading a project’s tables is a separate permission from reading the project itself, and the archive checked it before writing the tables’ definitions but not before writing their rows — so a member holding project access alone could name any table in the project and download its contents inside an archive. Table data is now withheld from anyone without that permission, and the export says which tables were left out.
Nothing changes for a member who can read the project’s tables. Nor is anything lost: such an archive already carried no table definitions, so restoring one never recreated any tables — the data in it was download-only. Worth checking: if you keep scheduled archives as backups, confirm the member they run as can read the project’s tables, or those archives hold configuration and no data. See Archive a Project.
-
A query assembled outside the platform, or an expression written inside it, can no longer carry SQL of its own. Several Analyze operations — allocate, melt, pivot, update, delete, table exports and view definitions — accept a query that was assembled elsewhere and sent along with the request. The platform used to reconstruct whatever arrived, which meant a crafted request from anything able to reach those operations could have run code inside the server. Such a request now rebuilds only the database-query pieces a genuine query is made of, and the text those pieces hold is checked too: a literal SQL fragment must be a single value rather than a statement, and a name that asks to skip quoting must be an ordinary identifier. Queries you build in the product are unaffected, as are column names containing spaces, dots or quotation marks — those are quoted for you and always were.
The same rule applies to an expression you type into a data mapper or a step’s filter, which is built inside the platform and so was never checked, even though it reaches a query all the same: an allocation step’s source filter is turned into SQL and put directly into the query’s
WHEREclause. Insidesqlalchemy.literal_columnonly, four shapes stop working. Text that is a subquery is refused, because that is the shape that reads a table the query never declared — build it withsqlalchemy.select(...),.scalar_subquery()for a single value or.subquery()for a table to select from. Text whose outermost operator isORis refused, because a condition added after it binds to only half of it — put brackets round it,(a OR b).XORis refused wherever it appears — write it as(a AND NOT b) OR (NOT a AND b). And text carrying a comment is refused, because a comment silently erases whatever the platform adds after it:--where it would run to the end of the statement, and#anywhere at all, including inside a quoted string and including Postgres’#>and#>>JSON path operators, because#opens a comment on MySQL-compatible warehouses such as StarRocks and which warehouse will run the expression is not known when it is written. If you need the character itself, pass it as a value withsqlalchemy.literal('#').Everything else is unchanged —
literal_column('current_date'), aCASE, a cast, a window function, a warehouse-specific function, a bracketed disjunction, andfunc.count(), which builds one of these for you. An export that supplies plain SQL rather than a pre-built query works exactly as before, and when an AI assistant checks an expression for you it names the shape it refused and what to write instead. See Reading Another Table From an Expression. -
Copying workflow steps now checks your access to the project you are copying from. The copy checked only the project you were copying into, so the source project — and the workspace it was named in — were taken on trust. A request built by hand could name any project and have that step’s full setup, including its connections and its SQL, recreated in a project of its own choosing. Both are now checked against the workspace you are signed in to, a copy asked to read out of a workspace you are not in is refused, and what is copied is filtered against your role in the source project rather than the destination. Copying between projects you can already open is unchanged, and the copy and paste buttons only ever worked within your own workspace. See Copy & Paste steps.
-
Editing a workflow with the AI assistant can no longer leave it unable to open. Where the assistant changed a workflow’s steps — the reported case was an Import CSV step — a stray, malformed entry could be written into the workflow’s saved structure, and from then on the workflow could not be opened, added to, or have a step removed or switched on or off. The places that read a workflow’s structure now step past such an entry instead of failing on it, so a workflow already left in this state opens again with nothing to repair, and the assistant’s save refuses a malformed entry with a clear error naming it rather than storing it or dropping it silently.
-
An Advanced workflow step tile no longer occasionally shows no run time on the canvas. Reopening a workflow could leave a step that had finished — its success mark and its row and column counts all present — showing no run duration in its footer, as though it had never run. The run history that fills in a step’s last and average run times sometimes failed to load behind the scenes, so the footer had nothing to show; it now loads reliably and the durations appear as expected. Nothing about how a step runs or what it produces changed. See Advanced Workflows.
-
A project’s own automation credential can no longer reorganise your workspace’s project folders, list them, or create projects. Every project has a credential of its own, which PlaidCloud uses to run that project’s workflows and to let its steps reach its data. It is meant to reach that one project and nothing else, and wherever a request names a project it always did. But a few requests name no project at all — creating, renaming, moving, copying and deleting the folders your projects are organised into, listing those folders, and creating a new project — and on those the credential was accepted simply for being valid. It is now refused on all of them, so it stays confined to its own project everywhere. Nothing changes for people: your own account is unaffected, as is anything a workflow step does within its own project. If your workspace has automation that manages projects this way — creating or removing projects, or reorganising the folders they sit in, from inside a workflow — it will now be refused, and the refusal names what it tried to do. That can be re-enabled for your workspace on request; ask support rather than reworking the automation. Not known to have been used maliciously; found while reviewing a folder-deletion message.
-
Listing what a project contains now requires access to that project. The call behind “what is in this project” — the one that returns the names and folder paths of a project’s workflows, steps, tables, hierarchies, editors and user-defined functions — checked that you were allowed to read projects in general, but never that you had any access to the project you named. Anyone signed in to the workspace could therefore list the contents of any project in it, including projects they cannot open. It is now checked the same way every other read of a project is, so you see only projects you have access to. Names and paths only were ever returned this way — no table data, no step configuration and no credentials. Nothing changes for a project you can already open.
-
Locking or unlocking a project now requires access to that project. Both actions checked only that you were allowed to lock projects at all, never that you held any role on the one you named — so anyone able to lock a project could lock or unlock any project in the workspace, including ones they cannot open. They are now checked the same way enabling and disabling a project already were. Worth checking: a project left locked or unlocked this way stays as it was left; if a project’s locked setting is not what you expect, set it on the project’s configuration screen.