edit_table_blocks.
Shape a call as one action block
edit_table_blocks has seven actions: create, update, reshape, copy, delete, set_time_rollup, and update_calendar. Fill exactly one block named for the action, and put that action’s fields inside it.
scenariosits beside the block and applies to it. It is also accepted inside the block; a call that names two different Scenarios in the two places is refused.- A field the chosen action does not take is refused, with
accepted_fieldslisting that action’s own fields plusscenario.
Write through the saved table
First read the table withinspect_table_blocks to get its visible row and column references:
update, with the same scenario as the read, so both resolve the same saved table:
- A row with no Date scope takes
formula. A row that runs across time takesdefault_formulas, with anactualsentry, aforecastentry, or both. An entry you leave out stays unchanged. clear_formula: truein place offormularemoves the formula the row owns for that range.- The server derives the Variable, the cell address, the formula range, and the write permissions from the visible target. Copy references from the inspection result, such as
Gross Profit#3f2, instead of inventing IDs, positions, or range identifiers.
Tables that save a comparison
A table that saves a Scenario or period comparison takes writes too. Name the selected Scenario’s own column, with or without the comparison qualifier the read printed, and the write lands in that Scenario. A compared Scenario’s column, a compared period’s column, and a difference column take no write: the refusal says the table’s saved comparison is left out, because those columns show values saved in another Scenario or period, or calculated.Formulas the items beneath a row inherit
child_defaults on a row_updates or column_updates entry holds the formulas the cells beneath the row inherit, one entry per breakdown Dimension at any depth:
- Each entry names its
dimensionand carriesactuals,forecast, or, on a timeless table,formula. Onerow_updatesentry can set the row’s own formula and its children’s together. - A deeper level’s entry is saved on the level above it. In Total by Owner by Deal, the Deal entry is the formula on
Total[Owner]. - An axis row, such as
Total[Stage], sets the formula for every item’s children; an item row, such asTotal[Discovery], sets it for that item only. clear: trueon an entry removes an owned timeless child formula; dated ranges clear throughactualsorforecast. The item’s ownclear_formularemoves only the parent row’s formula.
Create a visible derived row
A new Variable can be defined and placed on an existing saved table in the same change.structure.insert names the side, the new Variable, and its formula:
structure inserts, then moves, then removes rows and columns. A removal drops a row or column and its subtree from this table, never the objects themselves, and every Variable and Dimension must keep a row or column on at least one table. The same update can write the cells of inserted rows with cell_updates or values.
To start a new table instead, use create with its complete rows and columns:
default_formulas open over that Dimension, so every item calculates the formula, under the same condition a later row_updates on that row writes.
Create several dependent tables in one call
When a build needs more than one table, and a later table’s formulas name Variables an earlier table declares, put the tables in atables list inside one create instead of making one call per table:
tablesholds up to 20 tables. They save in list order in one change, so a formula in the second table can name a Variable the first table declares.- Two entries that name the same new
pageshare it. - Each entry carries its own
name,page,rows,columns, and settings.scenarioanddry_runsit on the request and apply to every entry. - The response holds one receipt per table, in list order, and every table shares one
change_log_id. A refusal of any table refuses them all and names the table.
A new dated row gets a time rollup
A formula on a month row governs month cells only. Quarter, half-year, and year cells read the Variable’s time rollup.- A
createorinsertrow may namerollup:SUM,LAST, orAVERAGE. - When it names none and the table’s periods are at the Model’s base grain, the save writes the rollup the request implies, at every grain coarser than the base, for Actuals and Forecast:
SUMfor a number with no aggregation or withSUMorCOUNT, andLASTforaggregation_function: LAST. It writes none for a timelessformula,format: PERCENTAGE, a value that is not a number, or any other aggregation. - A row created on a table whose periods are quarters or years, or on a table without Date, gets no implied rollup.
- The receipt states the implied rollups in one
default_rollupissue, and does not list them asrollupsor count them asdefault_formulas. - A ratio row created without
format: PERCENTAGEgetsSUM, so its year cell adds the monthly ratios.set_time_rollup, or a namedrollup, corrects it.
default_formulas formula written through a table whose periods are coarser than the base grain, such as a yearly table in a monthly Model, is saved at that coarser grain, and the receipt warns: the year cells compute the formula whatever their month cells hold, and the month cells do not read it. Write the formula on a row of a base-grain table, or in a variables entry, when it should govern the base periods.
A breakdown’s totals are written for you
When a table breaks a Variable down,child_defaults on the deepest axis row is the formula for the lines, saved on each line’s full path. The save then gives every coarser level the tables show a default that sums the level beneath it, one ordinary formula per level, and the receipt lists them: “Revenue’s level defaults, which add up its [Customer, Line, Product] lines at each level the tables show: saved Revenue[Customer, Product], Revenue[Product] and Revenue.”
- A value set on any row reaches every total above it.
- A formula an author writes at a level replaces the default there, and a default edited into other text stays with its author.
- The sums exist only while a line formula claims the lines. Clearing the line formula removes the sums left in its range.
- A Variable with
format: PERCENTAGEgets no sums and no0on its lines. Each level above them gets the line formula orNULL, and the receipt states which: “saved the line formula on [rows], so each of those rows computes that formula from its own inputs”, or “saved NULL on [rows], which reads blank, where the lines hold typed-in numbers or several formulas, or where their formula takes its own row’s item of a dimension that row lacks or reads a variable with no value on that row”. - A row’s
numberFormatis display only and changes no formula. - Each sum adds up the one shown level beneath it, never every line dimension at once. A total above lines whose formula has no Date is saved without Date too.
- A sum a person or Ari saved at a level is left alone, even when it is spelled exactly as the sync spells its own sums. The sync replaces or removes only the formulas it wrote itself, which a
variableread markswriter: "level_default_sync". - When one call creates several tables, each table’s receipt lists the level defaults for every Variable that table shows, including a Variable a row names only by reference.
- A
createdry run runs the same totals step and rolls it back, so itsmodel_effectscarry the statements the committed receipt puts underlevel_defaults, for each table in the call.
Add items and write their values in one call
- An
updateadds the items thatdimensions[].add_itemsorreplace_itemsnames before it resolvesvaluesandcell_updates, so one call can addE9to Entity and write["E9", 42]invalues. - A
create, or an update that adds rows, can also fill a mapping column on the rows it adds. A Department cell on a new employee row saves the one quoted item,"Sales"; a new item joins the Dimension’s list; and a value that is not one item is refused before anything saves, naming the cell. - Cells of one lookup save in one mapping write, so filling 400 Departments costs about the same as filling one.
shared_mapping_changed notice names the first changed row and its item before and after, and counts the rest: “The shared mapping changed: EMP-001’s Department moved from Engineering to Operations, and 3 more rows changed. Other tables and periods that use it can also change.” A first assignment reads “is now Sales”, and a cleared cell “was cleared; it was Sales”. Every table that reads the mapping recalculates in the background after the call returns; inspect_dimension_mappings lists those tables.
Where a timeless formula is written
formula and clear_formula write a Variable’s timeless formula, which applies in every period, Actuals and Forecast alike. default_formulas.actuals and default_formulas.forecast write formulas limited to Actuals or to Forecast, and create and update both accept them.
- A
createwrites a timelessformulafor a Variable it makes, including on a row of a table with Date columns. It refuses one on a row that places an existing Variable. - An
updatewrites a timelessformulaon an undated row or column, and refuses one on a dated row or column. - Both refusals use the same sentence, which says where each kind of formula is written.
child_defaults clear on create goes through the same planner an update uses, so a child that owns no formula reports unchanged.
An axis that only lists items has no formula to edit
formula and clear_formula edit the formula of a calculated value: a Variable, a Dimension shown as a value through its mapping or formula, or the Variable that encloses a Dimension breakdown. An axis that only lists a Dimension’s items has no calculated value, so a formula edit aimed at it is refused with a reason instead of a resolution error. The reason:
- opens “this table axis shows its dimension with role DIMENSION: it lists the dimension’s members, and no calculated value is on either axis”;
- says that
dimensionsadd_items,remove_items,replace_items, andrename_itemsedit saved items, and that a retained breakdown edits its enclosing Variable’s formula; - adds that “a dimension axis whose role is VARIABLE holds one value of that dimension for each member on the other axis, and a formula on it saves the rule that calculates that value”.
role field’s description and the item-condition refusal carry that same sentence. A formula that generates a source-linked Dimension’s items has no write in the tool: the person writes it in a table, from the Dimension’s label-row menu, with Edit dimension formula.
Save a Variable’s formula without a table
When the requested formula has no visible table target, name the Variable in avariables entry. No table target is needed:
- The formula is saved on the Variable with one Date term at the Model’s base grain, the same address a plain row on a base-grain table writes. A later
row_updateswrite on a table that shows the Variable edits this formula instead of adding a rival. - The same entry takes the Variable’s settings, wherever it is read:
name,data_type,aggregation_function,preferred_time_property,format,decimal_places,currency, andvariance_colors. - Item edits on a Dimension still name a table that shows it.
Filter the items an axis shows
members on a row_updates or column_updates entry is the saved item filter of the selected axis. It takes one of two forms.
A list of item names replaces the filter, including a saved condition. [] clears it.
- The list may name
empty:None, the rows with no value. - Each name is checked against the Dimension’s hand-added items and the source’s item text, then, for a name those do not hold, against the calculation’s own item list. So an item a formula or mapping computes is saved, and so is a number written as the table’s rows write it, such as
13840.0. Date and number items match by their saved text, such as"2026-01-01 00:00:00+00". - A name the calculation does not hold either is reported under
unmatched. A list that names no item at all is refused with the Dimension’s first items. - Only an item filter may name
empty:None.add_items,replace_items,rename_items, and a mapped item namedempty:Noneare refused with “empty:None is the spelling of a dimension’s empty member, which holds the rows with no value and exists without being added”.
[`Employee ID`#403 where `Employee ID`#403.Department#2f5 = "Engineering"], so it can be written back unchanged, and a list read names the home of a Dimension the condition reads from outside the table under property_homes. When the condition’s text cannot be printed, the read reports {"saved": true, "shown": false, "reason": ...} instead. The reason is it reads a variable or dimension this read cannot name for this person for a property you cannot read, or it reads a variable or dimension that is not in this scenario for one the Scenario no longer holds, such as a deleted Dimension; when both apply, the permission reason is given. Only the list, definitions, and grid reads can tell the two apart, so an edit receipt gives the permission reason for either.
- Literals are quoted strings. A bare number is a reference offset, not an item.
Region not in {"West"}keeps every named item but West. The empty item has no value, so a comparison on it is unknown; a null check insidewherekeeps it:Region where (Region = null or not (Region in {"West"})).- A condition may read a Dimension mapped from the axis, such as
Employee where Status = "Active". A condition on a Dimension the axis is not mapped from is refused, and the refusal names the step that makes it readable:edit_dimension_mappingsmaps that Dimension from the axis, which gives each axis item one item. - A condition never reads a Variable.
Vendor where FutureSpend > 0is refused with “a member condition on Vendor reads only Vendor”, and the refusal names the step that works: place a Dimension as a value column on a table whose rows are the axis, give it a formula that reads the Variable, such asif(FutureSpend > 0, "Yes", "No"), and save that formula withedit_table_blocks. The Dimension then has one value per item, andVendor where HasFutureSpend = "Yes"stays current after the next import.
Total[West] names its axis. hidden on the same entry hides or shows the saved axis the selection belongs to, so hidden: true on an item row hides every item of that level.
When a receipt that lists every item would exceed the result allowance, each member_filters entry reports members_omitted, the count, in place of its members list, and the edit still answers outcome: applied.
Edit an address that holds several saved formulas
A table edit names an address: the Variable, its condition, and its formula range. Imports and older writes can leave more than one saved formula at one address.- An exact
$[...]formula outranks an inheriting[...]formula at its grain, and among formulas of the same form the newest save wins. So cells read one formula: the newest exact one when one exists, otherwise the newest inheriting one. - A
row_updates,child_defaults, orcell_updateswrite at such an address edits the formula the cells read, and deletes the older copies of the same form in the same change. The receipt names each deleted copy: “This write also deleted an older copy of a Forecast rule that Advertising carried at this address:1at[Vendor in any, Date.Month in any]. No cell read a deleted copy, so no value changed.” - An exact formula and an inheriting
[...]formula at the same grain are not copies. The write edits the exact one, keeps the inheriting one, and names it in the receipt.
duplicate_default_formula issue, which counts the copies and says that a write to the default deletes them. The default itself shows as defined here and can be written.
Set where a source’s rows sit on the calendar
Where an imported source’s rows sit on the calendar is one fact about the source, and asources entry on update or create states it once:
targetis the query reference a read prints undersources, andpreferred_time_propertyis one of the source’s date columns.- The write saves that column on every Variable and Dimension of the source in the same change. A
variablesordimensionsentry in the same request that sets its ownpreferred_time_propertywins for that object. - A column that is not a date column of the source is refused, naming the columns that are.
- An
updatethat carries onlysourcesneeds no table target.
Declare a mapping in the create that reads it
Acreate whose formulas read a mapped Dimension can declare the mapping in the same call, instead of calling edit_dimension_mappings first. The create’s dimensions entry takes target, keys, items, and catch_all, as edit_dimension_mappings map takes them:
A table formula or mapping write that would give a Dimension a second lookup is refused, and nothing saves, when the two lookups share no key and both reach every row of the same imported table, because the calculation could not choose between them for a row both match. Lookups that share a key, such as Account alone and Account with Account ID, are not refused: the more specific one wins and the other is its fallback, as Dimension mappings describes. The refusal names the Dimension and both lookups: target dimension "Direct Cash Flow Group" already has a mapping input keyed by [CF Classification Basis] that reaches the same imported source as the proposed input keyed by [CF Line ID]. Both inputs would match every source row, so "Direct Cash Flow Group" would have no defined mapping result. A key that is itself a mapped Dimension counts through the import it reaches.
- The mapping is written in the same change, before the rows, so a formula such as
sum(`Income Statement Amount`[`P&L Line` = "Revenue"])resolves in this call. The table, the Dimension, its items, and its rows commit together. itemsmaps single source values to fixed items, so a nonemptyitemsneeds exactly one key.- A mapping formula’s
conditionis saved as a relative[...]formula; a leading$before a nonempty condition is dropped. So when one lookup is keyed by Account and another by Account together with Account ID, a row the two-key lookup has no formula for falls back to the one-key formula instead of the catch-all. - The catch-all
[]is unchanged, and a formula saved as$[...]earlier keeps its exact condition until a mapping write names its row again. - The receipt’s
itemsentry for the Dimension carries the mapping’s facts:keys,rows_created,rows_updated,target_items, andcatch_all. - A refusal on either side saves nothing.
Set a table’s window and grain
window is the table’s own date range and grain.
- On a
create, it holdsstart,end, andgranularity. A dated table names its grain, such asMONTH; a timeless table namesNO_GRANULARITY, as thetablesexample above does. - On an
update, the range is{"type": "ABSOLUTE", "start": …, "end": …}, and{"inherit": true}clears the table’s own window. startandendaccept a plain calendar date, such as2026-02-01, as well as a full timestamp, andcreateandupdatesave the same window for either form.updatewithgrainmoves the table’s Date columns to that grain, so a monthly table asked forQUARTERshows quarter columns, and the receipt reports the moved Date column. A table whose Date header shows two grains at once, such as Year above Month, is refused a new grain.grainon a row or column node sets the display grain of a datetime axis only. On a Variable row it is refused, and the refusal states where a Variable’s grain comes from, such as “grain on a row or column sets the display grain of a datetime axis; “Revenue” has data type FLOAT. A variable’s default_formulas save at the table’s Date grain: the grain of its Date axis, which time sets on create and grain sets on update or reshape.” That sentence describes a formula written through a table; Save a Variable’s formula without a table states the grain avariablesentry saves at.
Write values into dated columns
- A
valueswrite names each Date column by the start of its period at the table’s grain. On a table with yearly columns,2024-01,2024,FY2024, and2024-01-01all write the 2024 cell;2024-02is refused as a date inside a YEAR period, and the refusal names the form that works. - A period outside the table’s window is refused with the window and the start or end that would hold it, such as “2025-12 is before this table’s window 2026-01…2026-12; a window that starts 2025-12-01 holds it”. A call may set
windowand write the new periods together. - A whole number such as
2026also selects a number item printed2026.0, and a row renamed in the same request resolves under either name. - A JSON number in exponent form saves as the same value in plain decimal digits, so
1.5e-3saves as0.0015; the formula grammar has no exponent literal. A number outside the 64-bit floating-point range is refused with “<literal>is outside the 64-bit floating-point range”. - Dated inputs in
valuesorcell_updates, and the periods areadbackselects, leave the table’s saved display window unchanged. A report that must show a requested start and end needswindowset on the same call, or the table keeps showing its old range with the new months outside it. A readback of selected months proves those cells, not the displayed range.
Write in a Scenario
scenario defaults to the Scenario in view, which can change between turns. Through MCP, that is the Scenario _context.layerId names, or Main. When a call that saved something omits scenario, each table receipt carries a scenario_warning issue that says which Scenario the write used:
- With a Scenario in view: “No scenario was named, so this call used
Breakeven Plan#4c1, the scenario the person is viewing. The scenario in view can change between turns.” - With none in view: “No scenario was named and none is in view, so this call used
Main.”
unchanged, and a formula_warning says the Scenario already reads this value from its parent, so the cell keeps following the parent and changes when the parent changes. A different value is saved as the Scenario’s own and holds through the parent’s later edits. Scenarios, Snapshots, and version history explains why.
Delete a Variable or Dimension
deletewith atargetalone removes the whole table, and deletes only the Variables and Dimensions that no other saved table still shows. An object another table shows stays there, with its formulas, values, and items.- No table owns an object. A
row_updatesorreshapewrite may take an object off the table it was created on while another table shows it; only removing its last occurrence needs it placed elsewhere first, or deleted outright. deletewith avariablesordimensionslist removes only the listed objects, wherever they are placed. An object on another table, or on no table, is reached by name; the named table only scopes the call. A name that matches no readable object is refused with “delete target … matches no readable variable or dimension”.- When other formulas, blocks, or settings still read one of the objects, the delete is refused and lists what reads it under where each object sits, such as “is shown on table Revenue” or “has no recorded table location”, ending “With force, the object is deleted and these references break.”
force: trueaccepts that those references break. forceon the delete covers every listed entry;forceon one entry covers that entry alone, so a call can force some entries and not others.updateentries do not takeforce.- A refused table delete opens with “Nothing was deleted” and the count of dependents. A completed one carries a
links_endissue, because links to the table in earlier chat messages no longer open it, and a table rebuilt in its place has a different identity. - Removing a Dimension item is refused, opening with “Nothing was removed”, while a formula, a drill-in, a chart or Canvas condition, a row on another table, or a filter that lists only that item names it. Manual sort orders, and filters that still list other items, drop the item instead.
A formula belongs to its Variable
Acreate row that names an existing Variable by its plain name places that Variable. Rows match names without regard to case, so Deferred revenue places Deferred Revenue.
A plain name adds to the Variable only where it holds nothing:
- a formula for a range or level that has none,
- a value at a cell that has none and that no formula of the Variable calculates, or
- a type or format that was not set.
- A formula calculates the cell unless it is pinned to one cell. An exact condition with an open term, such as
$[Date.Month in any], is a formula over every month. - A dated formula counts at the Model’s base grain and at the grain of the value given, so a formula saved from a quarterly table refuses a quarterly value.
- The generated formulas a breakdown’s save recorded as its own are judged by what they compute. The
0on the lines supplies what a blank cell reads, so a value on a line is an addition; the sum on a level calculates that level alone, so a value on the Variable’s own row is a replacement. - A value on a timeless Variable that holds nothing is an addition.
- Every aggregation that is set,
DO_NOT_AGGREGATEincluded, is a setting a plain name does not replace. - The check does not read which items a condition names, so a formula for one item refuses a value on another item’s cell.
- The Variable’s reference, such as
Budget#3f9, writes that Variable and replaces what it holds. new: trueon the row creates a separate Variable with the same name and leaves the existing one as it is. Throughout a request withnew: true, in rows, columns, formulas, values,variablesentries, and later tables of the same create, the plain name means the new Variable, and each existing namesake answers only to its reference.
items entry for a reused object carries:
home, the table it was first created on, when that table exists and is readable;added, with therules,values, andsettingsthe save gave it;beside_rules, the count of formulas the Variable already held that calculate its cells, which is 0 whenever values were added;rule: "replaced"when a write by reference replaced a formula the object already had, in Main or in the Scenario being edited;- and, on an
updateorreshapeentry for a reused Variable,level_defaults, the sums and0the save’s breakdown added to it or removed from it.
default_formulas by its reference, such as Revenue#3f2, while placing it on another table rewrites the formula every table reads. When the formula it replaced was a formula, the receipt names it and the address the Variable carried it at. Writing a value over a plain number, quoted text, a date, or null states no replaced formula; the committed edit’s previousText carries the old value instead. Placing a Variable without new defaults leaves its existing formula alone.
Names and references
- A stale table reference whose name no longer exists resolves by its suffix when the suffix has at least three hex digits and exactly one table carries it.
inspect_table_blockslistreports the move in arenamednote, such as “Vendors#083: no table has that name; its suffix matches the table now named “Anomalo Vendors"". - Formula names match case exactly. A formula that names
`Deferred revenue`when onlyDeferred Revenueexists is refused with the object it matches: “`Deferred revenue`matches the existing`Deferred Revenue`(names match without case); formula names match case exactly, …”. - A reference field and formula text accept the same written form of a namesake. The short suffix a readback prints, such as
Currency#3besideCurrency#8, names the object it prints for, and a suffix of three or more hex digits is checked against the object’s retained identity, so a reference issued for a deleted object never moves to a new namesake. - A backticked name that no object carries, such as
`Amount#3c2`, reads as the reference it quotes. In a table row or column, backticks still mark a literal new name.
Check before you save
A table write is atomic: the whole change saves, or none of it does. Onlycreate takes dry_run: true, which validates a new table without writing; edits to saved tables and deletions take no dry run. Validate and verify formula writes has the details.
Read back what you saved
- Ask for a readback in the same write with
readback.rowsandreadback.columns.rowsalone reads every column,columnsalone every top-level row, and a renamed Variable or Dimension resolves under either name.readback.depthadds child levels:1adds each row’s items,2theirs, andallevery level; omitted reads the selected rows alone.readback.alsoreads up to 3 other saved tables at the same change, each entry{"target", "rows", "columns", "depth"}with the readback’s own meanings: omittedrowsreads every top-level row, omittedcolumnsevery column, anddepthnests the same way. Each entry’s result comes back underreadback_alsoin request order. - An
update,reshape, ordeletemay carrybased_on: theas_ofof the table read, or thechange_log_idof the table write, it builds on. The edit saves either way. When someone else saved to the table after that point, the receipt adds achanged_since_readissue naming each save and who made it: a person by name, “a person in the app”, “Ari in another chat”, or “an automated process”, up to five saves and then a count. - Check the intended Scenario, representative dates and segments, formula origins, and the actual numbers. When the receipt carries warnings, read them before moving on. Validate and verify formula writes lists them.