Skip to main content
Glama

Create or update branch

layerz_update_branch
DestructiveIdempotent

Creates or updates a branch. With dataset_id, patches that branch's metadata (display_name, priority, source_hint, file_name, actuals_through). Without it, the branch named patch.display_name is updated when it exists and created otherwise, with no data source and no input rows. ops (the layerz_patch operations) are applied on the branch in the same call, as layerz_patch { branch_id } would: a scenario that changes a value is one call; the result then carries patch. priority is rejected on the default branch. An explicit actuals_through pins the real/forecast cutover (actuals_through_locked: true: source syncs stop rewriting it); null resets it to auto. Returns { branch, created }. Persists one version labelled with summary. Not advertised to read-only keys.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "summary": "<summary>",
      "patch": "<patch>"
    },
    "name": "layerz_update_branch"
  }
}

Input Schema

NameRequiredDescriptionDefault
opsNoOperations applied on this branch in the same call, in the `layerz_patch` `ops` format (value writes land as the branch overlay).
patchYes
summaryYesShort note (3–100 chars) describing the change, stored as the label of the resulting version. Examples: "Renamed Revenue to Net Revenue", "Imported 2024 OPEX from Excel".
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
dataset_idNoBranch to update. Absent: the branch named `patch.display_name` is updated when it exists, created otherwise.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changed
    • changedInput schema / properties / ops / description
      Previous value: -"`layerz_patch` operations applied on this branch in the same call."New value: +"Operations applied on this branch in the same call, in the `layerz_patch` `ops` format (value writes land as the branch overlay)."
    • addedInput schema / properties / ops / items / additionalProperties
      Added value: +{}
    • removedInput schema / properties / ops / items / oneOf
      Removed value: -[
      -  {
      -    "properties": {
      -      "aggregation": {
      -        "enum": [
      -          "sum",
      -          "average",
      -          "stock",
      -          "first"
      -        ],
      -        "type": "string"
      -      },
      -      "axis": {
      -        "description": "mini_table column axis: 'time' (periods, default), 'branches', or 'list' (list entries + Total)",
      -        "enum": [
      -          "time",
      -          "branches",
      -          "list"
      -        ],
      -        "type": "string"
      -      },
      -      "branches": {
      -        "description": "mini_table compared branch ids (axis=branches); first = écart base",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "bridge_config": {
      -        "properties": {
      -          "axis": {
      -            "description": "Bridge dimension: 'time' (default, delta start→end period) or 'branches' (gap between two branches at one period — budget vs actual waterfall).",
      -            "enum": [
      -              "time",
      -              "branches"
      -            ],
      -            "type": "string"
      -          },
      -          "branches": {
      -            "description": "Branch ids compared when axis=branches: [from, to].",
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "contributions": {
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "end_period": {
      -            "maxLength": 50,
      -            "type": "string"
      -          },
      -          "endpoint": {
      -            "description": "Single endpoint item (stock/balance) read at start & end periods",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "endpoint_branch": {
      -            "description": "Read endpoint + contributions under this branch basis (axis=time only).",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "residual_label": {
      -            "maxLength": 200,
      -            "type": "string"
      -          },
      -          "start_period": {
      -            "maxLength": 50,
      -            "type": "string"
      -          }
      -        },
      -        "required": [
      -          "endpoint"
      -        ],
      -        "type": "object"
      -      },
      -      "by_branch": {
      -        "description": "Chart only: one styled series per branch; false reverts to the checked-out view.",
      -        "type": "boolean"
      -      },
      -      "cagr": {
      -        "description": "mini_table (axis=time): show the trailing CAGR column. Default true",
      -        "type": "boolean"
      -      },
      -      "chart_type": {
      -        "enum": [
      -          "line",
      -          "bar",
      -          "area",
      -          "bridge"
      -        ],
      -        "type": "string"
      -      },
      -      "check": {
      -        "anyOf": [
      -          {
      -            "properties": {
      -              "tolerance": {
      -                "exclusiveMinimum": 0,
      -                "type": "number"
      -              }
      -            },
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Flags the line as a control judged on its own value: a plain amount passes when within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals); a formula that is itself a comparison / AND / OR / NOT passes when true. `null` removes the check. Failing periods surface in `layerz_read` under `health`, non-blocking."
      -      },
      -      "collapsed": {
      -        "description": "fold the group by default: a section with children, a Σ aggregator or a list-mode line opens collapsed in the web grid and its rows start hidden under the Excel outline (+/−). false unfolds. View state, outside the blueprint and the diffs",
      -        "type": "boolean"
      -      },
      -      "comment": {
      -        "anyOf": [
      -          {
      -            "maxLength": 2000,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Free-form annotation on the item (null clears it)."
      -      },
      -      "compare_to": {
      -        "anyOf": [
      -          {
      -            "properties": {
      -              "branch_id": {
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "display": {
      -                "enum": [
      -                  "abs",
      -                  "pct",
      -                  "both"
      -                ],
      -                "type": "string"
      -              },
      -              "mode": {
      -                "enum": [
      -                  "branch",
      -                  "prev_period",
      -                  "prev_year"
      -                ],
      -                "type": "string"
      -              },
      -              "thresholds": {
      -                "properties": {
      -                  "green": {
      -                    "type": "number"
      -                  },
      -                  "red": {
      -                    "type": "number"
      -                  }
      -                },
      -                "required": [
      -                  "green",
      -                  "red"
      -                ],
      -                "type": "object"
      -              }
      -            },
      -            "required": [
      -              "mode"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "KPI native comparison; null clears it."
      -      },
      -      "default_branch": {
      -        "anyOf": [
      -          {
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Dashboard-only: branch checked out when this dashboard opens; null clears it."
      -      },
      -      "format": {
      -        "description": "Number format name. Pre-installed: default, decimal_2, decimal_neg, integer, multiple, percent, percent_neg, percent_2, date_dmy, date_dmmmyy, date_mmmyy, date_dmmm (+ the magic `date`, and `currency`/`currency_2` — resolved live from the FINANCE.md `currency` code: `$1,234` for USD, `1 234 €` for EUR). Custom names refer to entries in model.formats — add one with the `meta` op `formats` field (same batch OK); the excel_format follows Excel / Google Sheets, bracket colours and conditions included (`[Green]0;[Red](0);-` paints negatives red on the web and in Excel). An unknown name is rejected with code UNKNOWN_FORMAT listing what is available (`percent` is the current name of the legacy `\"%\"`). Full catalog with each excel_format and rendered positive/negative/zero examples (`default` = dash-for-zero accounting style, `integer` = plain 0): MCP resource `format-spec://reference`.",
      -        "maxLength": 50,
      -        "type": "string"
      -      },
      -      "formula": {
      -        "maxLength": 2000,
      -        "type": "string"
      -      },
      -      "inputs": {
      -        "description": "Inputs override of a `formula` item (item UIDs or same-batch temp ids), derived from the expression when omitted. Ignored on every other role: a `balance` takes its flows from its children, an aggregator sums them.",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "item_style": {
      -        "enum": [
      -          "normal",
      -          "subtotal",
      -          "total",
      -          "kpi"
      -        ],
      -        "type": "string"
      -      },
      -      "list_mode": {
      -        "description": "Chart only: 'split' (default) = one series per list element, 'total' = the list-backed item's aggregate as one series.",
      -        "enum": [
      -          "split",
      -          "total"
      -        ],
      -        "type": "string"
      -      },
      -      "list_total": {
      -        "description": "List-mode only: show the list's total (aggregate row values). Default off; forced ON while the aggregate is referenced.",
      -        "type": "boolean"
      -      },
      -      "liste": {
      -        "description": "mini_table list whose entries become the columns (axis=list)",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "liste_ref": {
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "monitor": {
      -        "anyOf": [
      -          {
      -            "properties": {
      -              "assert": {
      -                "maxLength": 200,
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "label": {
      -                "maxLength": 200,
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "assert"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Deprecated (MDK 0.13.0) — use `check`. A canonical assert is converted, any other rule is rejected; `null` removes the check."
      -      },
      -      "name": {
      -        "description": "New display label (also the formula identifier)",
      -        "maxLength": 200,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "op": {
      -        "const": "update",
      -        "type": "string"
      -      },
      -      "opening_balance": {
      -        "type": "number"
      -      },
      -      "parent": {
      -        "anyOf": [
      -          {
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "New parent UID (null to move to root)"
      -      },
      -      "period_mode": {
      -        "description": "kpi / mini_table period mode. 'ytd' shows the year to date: the cumulative from January through the target period (each column for a time-axis mini_table). Flows are summed, an `average` line averaged, a `stock` line read at the period, and a ratio line (formula `a / b`) recomputed on the cumulated operands. Branch columns, écarts and the KPI comparison follow (prev_year = year to date of the same month a year earlier). Default 'period'.",
      -        "enum": [
      -          "period",
      -          "ytd"
      -        ],
      -        "type": "string"
      -      },
      -      "period_window": {
      -        "anyOf": [
      -          {
      -            "properties": {
      -              "end": {
      -                "maxLength": 20,
      -                "type": "string"
      -              },
      -              "fit": {
      -                "enum": [
      -                  "data",
      -                  "full"
      -                ],
      -                "type": "string"
      -              },
      -              "start": {
      -                "maxLength": 20,
      -                "type": "string"
      -              }
      -            },
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Display period window of a chart / kpi sparkline / time mini_table. `start`/`end` are period labels at the widget's grain (bounds independent — either alone is valid); `fit` governs the unset bounds: 'data' (the default, absent field included) auto-fits to the periods actually carrying data and follows imports, 'full' spans the whole timeline. `null` clears it (back to fit-to-data)."
      -      },
      -      "position": {
      -        "anyOf": [
      -          {
      -            "properties": {
      -              "col": {
      -                "maximum": 11,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "row": {
      -                "maximum": 400,
      -                "minimum": 0,
      -                "type": "integer"
      -              }
      -            },
      -            "required": [
      -              "col",
      -              "row"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "dashboard-child pinned grid origin {col 0–11, row ≥ 0}: the widget sits at these cells (pushed down when it collides with an earlier pinned widget). Absent = flow placement (first-fit dense in sort order — a new widget fills the topmost free hole); null clears the pin. The web canvas pins every widget on the first drag"
      -      },
      -      "role": {
      -        "description": "Change the item role. Role of the item. assumption: a typed input (value / values / timeline_values), the only role a branch overlays. formula: a computed transformation (formula). formula with no expression and children: an aggregator that sums its children (a subtotal value; a nested section is structural grouping with no value). callup: a typed mirror of one source whose value flows into its parent (source): balance flows, a value surfaced in a section or subtotal; a formula references its source directly instead. balance: a rolling stock (opening_balance) that sums its callup-child flows. section: structural container, no value. dashboard / chart / kpi / mini_table: presentational. A formula carrying both an expression and children is rejected (FORMULA_EXPR_AND_CHILDREN). A single bare reference written as a formula is auto-posed as a callup mirror, unless it pins a `timeline_ref` or an `aggregation` different from its source (then it stays a formula).",
      -        "enum": [
      -          "assumption",
      -          "formula",
      -          "callup",
      -          "balance",
      -          "section",
      -          "chart",
      -          "dashboard",
      -          "kpi",
      -          "mini_table"
      -        ],
      -        "type": "string"
      -      },
      -      "row_break": {
      -        "description": "dashboard-child line break (flow widgets only): start this widget on a fresh grid row. Inert once the widget has a position",
      -        "type": "boolean"
      -      },
      -      "row_styles": {
      -        "additionalProperties": {
      -          "enum": [
      -            "normal",
      -            "subtotal",
      -            "total",
      -            "kpi"
      -          ],
      -          "type": "string"
      -        },
      -        "description": "mini_table per-row style override { <row UID / temp ID>: 'normal' | 'subtotal' | 'total' | 'kpi' }; an absent key keeps the row item's own style, a key outside `rows` is dropped, {} clears every override",
      -        "propertyNames": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "object"
      -      },
      -      "rows": {
      -        "description": "mini_table curated row item UIDs / temp IDs / names",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "series": {
      -        "description": "Chart series UIDs",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "series_defs": {
      -        "description": "Per-series branch; supersedes `series`.",
      -        "items": {
      -          "properties": {
      -            "branch_id": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "uid": {
      -              "minLength": 1,
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "uid"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "source": {
      -        "description": "Callup source UID",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "span": {
      -        "description": "dashboard-child grid footprint (chart/kpi/mini_table): cols on the 12-column grid × 140-px row units. Defaults: kpi 3×1, chart/mini_table 6×2",
      -        "properties": {
      -          "cols": {
      -            "maximum": 12,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "rows": {
      -            "maximum": 4,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "sparkline": {
      -        "description": "KPI trend mini-chart.",
      -        "type": "boolean"
      -      },
      -      "target": {
      -        "description": "KPI/mini_table target UID",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "target_period": {
      -        "maxLength": 50,
      -        "type": "string"
      -      },
      -      "timeline_ref": {
      -        "enum": [
      -          "constant",
      -          "monthly",
      -          "yearly",
      -          "quarterly"
      -        ],
      -        "type": "string"
      -      },
      -      "timeline_values": {
      -        "additionalProperties": {
      -          "anyOf": [
      -            {
      -              "anyOf": [
      -                {
      -                  "type": "number"
      -                },
      -                {
      -                  "type": "null"
      -                }
      -              ]
      -            },
      -            {
      -              "items": {
      -                "anyOf": [
      -                  {
      -                    "type": "number"
      -                  },
      -                  {
      -                    "type": "null"
      -                  }
      -                ]
      -              },
      -              "type": "array"
      -            }
      -          ]
      -        },
      -        "description": "Periodic values, keyed by context. List-mode item: one series per list entry, keyed by the element UID, label, or a `list_create` temp id of the same batch (a temp id is scoped to the batch that declares it; later batches key by label or UID). On `update` the map merges element by element: entries it does not name keep their series (send `[]` to clear one); on `create` / `replace` it is the full set. Non-list item: a sparse per-period patch keyed by period id (`{\"2026-06\": -119.19}`, keys YYYY / YYYY-MM / YYYY-Qn) that rewrites the named cells of the typed `values` series and leaves the rest intact; a full series keyed by a canonical grain (`monthly` / `quarterly` / `yearly` / `constant`) is import-owned and rejected here. A single number is coerced to a 1-element array. List cells left unset read as 0 (no forward-fill).",
      -        "propertyNames": {
      -          "type": "string"
      -        },
      -        "type": "object"
      -      },
      -      "uid": {
      -        "description": "Existing item UID to update",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "unit": {
      -        "description": "mini_table amount scaling: 'none' (default), 'k' (thousands), 'm' (millions), 'auto' (per-table scale); %, multiples and dates are not divided",
      -        "enum": [
      -          "none",
      -          "k",
      -          "m",
      -          "auto"
      -        ],
      -        "type": "string"
      -      },
      -      "value": {
      -        "anyOf": [
      -          {
      -            "type": "number"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "values": {
      -        "items": {
      -          "anyOf": [
      -            {
      -              "type": "number"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ]
      -        },
      -        "type": "array"
      -      },
      -      "variance": {
      -        "description": "mini_table écart columns (axis=branches)",
      -        "properties": {
      -          "abs": {
      -            "type": "boolean"
      -          },
      -          "color": {
      -            "type": "boolean"
      -          },
      -          "pct": {
      -            "type": "boolean"
      -          }
      -        },
      -        "type": "object"
      -      }
      -    },
      -    "required": [
      -      "op",
      -      "uid"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "aggregation": {
      -        "enum": [
      -          "sum",
      -          "average",
      -          "stock",
      -          "first"
      -        ],
      -        "type": "string"
      -      },
      -      "axis": {
      -        "description": "mini_table column axis: 'time' (periods, default), 'branches', or 'list' (list entries + Total)",
      -        "enum": [
      -          "time",
      -          "branches",
      -          "list"
      -        ],
      -        "type": "string"
      -      },
      -      "branches": {
      -        "description": "mini_table compared branch ids (axis=branches); first = écart base",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "bridge_config": {
      -        "properties": {
      -          "axis": {
      -            "description": "Bridge dimension: 'time' (default, delta start→end period) or 'branches' (gap between two branches at one period — budget vs actual waterfall).",
      -            "enum": [
      -              "time",
      -              "branches"
      -            ],
      -            "type": "string"
      -          },
      -          "branches": {
      -            "description": "Branch ids compared when axis=branches: [from, to].",
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "contributions": {
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "end_period": {
      -            "maxLength": 50,
      -            "type": "string"
      -          },
      -          "endpoint": {
      -            "description": "Single endpoint item (stock/balance) read at start & end periods",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "endpoint_branch": {
      -            "description": "Read endpoint + contributions under this branch basis (axis=time only).",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "residual_label": {
      -            "maxLength": 200,
      -            "type": "string"
      -          },
      -          "start_period": {
      -            "maxLength": 50,
      -            "type": "string"
      -          }
      -        },
      -        "required": [
      -          "endpoint"
      -        ],
      -        "type": "object"
      -      },
      -      "by_branch": {
      -        "description": "Chart only: plot one styled series per branch instead of the checked-out view.",
      -        "type": "boolean"
      -      },
      -      "cagr": {
      -        "description": "mini_table (axis=time): show the trailing CAGR column. Default true",
      -        "type": "boolean"
      -      },
      -      "chart_type": {
      -        "enum": [
      -          "line",
      -          "bar",
      -          "area",
      -          "bridge"
      -        ],
      -        "type": "string"
      -      },
      -      "check": {
      -        "description": "Flags the line as a control judged on its own value at every period: a plain amount passes when within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals, so a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (\"Revenue >= 0\") passes when true. Assumption and formula only. Failing periods surface in `layerz_read` under `health`, non-blocking.",
      -        "properties": {
      -          "tolerance": {
      -            "exclusiveMinimum": 0,
      -            "type": "number"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "collapsed": {
      -        "description": "fold the group by default: a section with children, a Σ aggregator or a list-mode line opens collapsed in the web grid and its rows start hidden under the Excel outline (+/−). false unfolds. View state, outside the blueprint and the diffs",
      -        "type": "boolean"
      -      },
      -      "comment": {
      -        "anyOf": [
      -          {
      -            "maxLength": 2000,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Free-form annotation on the item (hypothesis source, rationale, review note)."
      -      },
      -      "compare_to": {
      -        "description": "KPI native comparison: a delta vs another branch (`mode:\"branch\"` + `branch_id`) or a shifted period (`prev_period`/`prev_year`). Rendered as the value plus a signed delta %.",
      -        "properties": {
      -          "branch_id": {
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "display": {
      -            "enum": [
      -              "abs",
      -              "pct",
      -              "both"
      -            ],
      -            "type": "string"
      -          },
      -          "mode": {
      -            "enum": [
      -              "branch",
      -              "prev_period",
      -              "prev_year"
      -            ],
      -            "type": "string"
      -          },
      -          "thresholds": {
      -            "properties": {
      -              "green": {
      -                "type": "number"
      -              },
      -              "red": {
      -                "type": "number"
      -              }
      -            },
      -            "required": [
      -              "green",
      -              "red"
      -            ],
      -            "type": "object"
      -          }
      -        },
      -        "required": [
      -          "mode"
      -        ],
      -        "type": "object"
      -      },
      -      "default_branch": {
      -        "description": "Dashboard-only: branch checked out when this dashboard opens; overrides the model default.",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "format": {
      -        "description": "Number format name. Pre-installed: default, decimal_2, decimal_neg, integer, multiple, percent, percent_neg, percent_2, date_dmy, date_dmmmyy, date_mmmyy, date_dmmm (+ the magic `date`, and `currency`/`currency_2` — resolved live from the FINANCE.md `currency` code: `$1,234` for USD, `1 234 €` for EUR). Custom names refer to entries in model.formats — add one with the `meta` op `formats` field (same batch OK); the excel_format follows Excel / Google Sheets, bracket colours and conditions included (`[Green]0;[Red](0);-` paints negatives red on the web and in Excel). An unknown name is rejected with code UNKNOWN_FORMAT listing what is available (`percent` is the current name of the legacy `\"%\"`). Full catalog with each excel_format and rendered positive/negative/zero examples (`default` = dash-for-zero accounting style, `integer` = plain 0): MCP resource `format-spec://reference`.",
      -        "maxLength": 50,
      -        "type": "string"
      -      },
      -      "formula": {
      -        "maxLength": 2000,
      -        "type": "string"
      -      },
      -      "id": {
      -        "description": "Temp ID for intra-batch references — other create ops in the same batch can use this value as their `parent`, `source`, `target`, or `series` to wire references before the real UID is generated. Numeric (`_1`, `_2`) keeps it short; descriptive (`_starting_customers`) is fine up to 32 chars.",
      -        "maxLength": 32,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "inputs": {
      -        "description": "Inputs override of a `formula` item (item UIDs or same-batch temp ids), derived from the expression when omitted. Ignored on every other role: a `balance` takes its flows from its children, an aggregator sums them.",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "item_style": {
      -        "enum": [
      -          "normal",
      -          "subtotal",
      -          "total",
      -          "kpi"
      -        ],
      -        "type": "string"
      -      },
      -      "list_mode": {
      -        "description": "Chart only: how a list-backed series renders — 'split' (default) plots one series per list element, 'total' plots the item's aggregate as one series (a list total charted without a mirror formula).",
      -        "enum": [
      -          "split",
      -          "total"
      -        ],
      -        "type": "string"
      -      },
      -      "list_total": {
      -        "description": "List-mode only: show the list's total (aggregate row values). Default off; the total is forced ON while any formula/callup/parent/widget reads the aggregate.",
      -        "type": "boolean"
      -      },
      -      "liste": {
      -        "description": "mini_table list whose entries become the columns (axis=list)",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "liste_ref": {
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "monitor": {
      -        "description": "Deprecated (MDK 0.13.0) — use `check`. A canonical assert (\"ABS(value) < t\", \"== 0\") is converted; any other rule is rejected: put it in the line's formula and set `check: {}`.",
      -        "properties": {
      -          "assert": {
      -            "maxLength": 200,
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "label": {
      -            "maxLength": 200,
      -            "type": "string"
      -          }
      -        },
      -        "required": [
      -          "assert"
      -        ],
      -        "type": "object"
      -      },
      -      "name": {
      -        "description": "Display name",
      -        "maxLength": 200,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "op": {
      -        "const": "create",
      -        "type": "string"
      -      },
      -      "opening_balance": {
      -        "type": "number"
      -      },
      -      "parent": {
      -        "description": "Parent container: either an 8-char UID of an existing section/balance/dashboard, or a temp `id` from an earlier create op in the same batch (e.g. set `id: \"_pl\"` on a section create, then `parent: \"_pl\"` on each child item).",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "period_mode": {
      -        "description": "kpi / mini_table period mode. 'ytd' shows the year to date: the cumulative from January through the target period (each column for a time-axis mini_table). Flows are summed, an `average` line averaged, a `stock` line read at the period, and a ratio line (formula `a / b`) recomputed on the cumulated operands. Branch columns, écarts and the KPI comparison follow (prev_year = year to date of the same month a year earlier). Default 'period'.",
      -        "enum": [
      -          "period",
      -          "ytd"
      -        ],
      -        "type": "string"
      -      },
      -      "period_window": {
      -        "anyOf": [
      -          {
      -            "properties": {
      -              "end": {
      -                "maxLength": 20,
      -                "type": "string"
      -              },
      -              "fit": {
      -                "enum": [
      -                  "data",
      -                  "full"
      -                ],
      -                "type": "string"
      -              },
      -              "start": {
      -                "maxLength": 20,
      -                "type": "string"
      -              }
      -            },
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Display period window of a chart / kpi sparkline / time mini_table. `start`/`end` are period labels at the widget's grain (bounds independent — either alone is valid); `fit` governs the unset bounds: 'data' (the default, absent field included) auto-fits to the periods actually carrying data and follows imports, 'full' spans the whole timeline. `null` clears it (back to fit-to-data)."
      -      },
      -      "position": {
      -        "anyOf": [
      -          {
      -            "properties": {
      -              "col": {
      -                "maximum": 11,
      -                "minimum": 0,
      -                "type": "integer"
      -              },
      -              "row": {
      -                "maximum": 400,
      -                "minimum": 0,
      -                "type": "integer"
      -              }
      -            },
      -            "required": [
      -              "col",
      -              "row"
      -            ],
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "dashboard-child pinned grid origin {col 0–11, row ≥ 0}: the widget sits at these cells (pushed down when it collides with an earlier pinned widget). Absent = flow placement (first-fit dense in sort order — a new widget fills the topmost free hole); null clears the pin. The web canvas pins every widget on the first drag"
      -      },
      -      "role": {
      -        "description": "Role of the item. assumption: a typed input (value / values / timeline_values), the only role a branch overlays. formula: a computed transformation (formula). formula with no expression and children: an aggregator that sums its children (a subtotal value; a nested section is structural grouping with no value). callup: a typed mirror of one source whose value flows into its parent (source): balance flows, a value surfaced in a section or subtotal; a formula references its source directly instead. balance: a rolling stock (opening_balance) that sums its callup-child flows. section: structural container, no value. dashboard / chart / kpi / mini_table: presentational. A formula carrying both an expression and children is rejected (FORMULA_EXPR_AND_CHILDREN). A single bare reference written as a formula is auto-posed as a callup mirror, unless it pins a `timeline_ref` or an `aggregation` different from its source (then it stays a formula).",
      -        "enum": [
      -          "assumption",
      -          "formula",
      -          "callup",
      -          "balance",
      -          "section",
      -          "chart",
      -          "dashboard",
      -          "kpi",
      -          "mini_table"
      -        ],
      -        "type": "string"
      -      },
      -      "row_break": {
      -        "description": "dashboard-child line break (flow widgets only): start this widget on a fresh grid row. Inert once the widget has a position",
      -        "type": "boolean"
      -      },
      -      "row_styles": {
      -        "additionalProperties": {
      -          "enum": [
      -            "normal",
      -            "subtotal",
      -            "total",
      -            "kpi"
      -          ],
      -          "type": "string"
      -        },
      -        "description": "mini_table per-row style override { <row UID / temp ID>: 'normal' | 'subtotal' | 'total' | 'kpi' }; an absent key keeps the row item's own style, a key outside `rows` is dropped, {} clears every override",
      -        "propertyNames": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "object"
      -      },
      -      "rows": {
      -        "description": "mini_table curated row item UIDs / temp IDs / names",
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "series": {
      -        "items": {
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "series_defs": {
      -        "description": "Per-series branch: supersedes `series`. Each entry plots one item under a specific branch (e.g. Revenue@budget vs Revenue@actuals). `uid` accepts a temp id.",
      -        "items": {
      -          "properties": {
      -            "branch_id": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "uid": {
      -              "minLength": 1,
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "uid"
      -          ],
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "source": {
      -        "description": "Callup source UID or temp ID",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "span": {
      -        "description": "dashboard-child grid footprint (chart/kpi/mini_table): cols on the 12-column grid × 140-px row units. Defaults: kpi 3×1, chart/mini_table 6×2",
      -        "properties": {
      -          "cols": {
      -            "maximum": 12,
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          "rows": {
      -            "maximum": 4,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "sparkline": {
      -        "description": "KPI trend mini-chart under the value.",
      -        "type": "boolean"
      -      },
      -      "target": {
      -        "description": "KPI/mini_table target UID or temp ID",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "target_period": {
      -        "maxLength": 50,
      -        "type": "string"
      -      },
      -      "timeline_ref": {
      -        "enum": [
      -          "constant",
      -          "monthly",
      -          "yearly",
      -          "quarterly"
      -        ],
      -        "type": "string"
      -      },
      -      "timeline_values": {
      -        "additionalProperties": {
      -          "anyOf": [
      -            {
      -              "anyOf": [
      -                {
      -                  "type": "number"
      -                },
      -                {
      -                  "type": "null"
      -                }
      -              ]
      -            },
      -            {
      -              "items": {
      -                "anyOf": [
      -                  {
      -                    "type": "number"
      -                  },
      -                  {
      -                    "type": "null"
      -                  }
      -                ]
      -              },
      -              "type": "array"
      -            }
      -          ]
      -        },
      -        "description": "Periodic values, keyed by context. List-mode item: one series per list entry, keyed by the element UID, label, or a `list_create` temp id of the same batch (a temp id is scoped to the batch that declares it; later batches key by label or UID). On `update` the map merges element by element: entries it does not name keep their series (send `[]` to clear one); on `create` / `replace` it is the full set. Non-list item: a sparse per-period patch keyed by period id (`{\"2026-06\": -119.19}`, keys YYYY / YYYY-MM / YYYY-Qn) that rewrites the named cells of the typed `values` series and leaves the rest intact; a full series keyed by a canonical grain (`monthly` / `quarterly` / `yearly` / `constant`) is import-owned and rejected here. A single number is coerced to a 1-element array. List cells left unset read as 0 (no forward-fill).",
      -        "propertyNames": {
      -          "type": "string"
      -        },
      -        "type": "object"
      -      },
      -      "unit": {
      -        "description": "mini_table amount scaling: 'none' (default), 'k' (thousands), 'm' (millions), 'auto' (per-table scale); %, multiples and dates are not divided",
      -        "enum": [
      -          "none",
      -          "k",
      -          "m",
      -          "auto"
      -        ],
      -        "type": "string"
      -      },
      -      "value": {
      -        "anyOf": [
      -          {
      -            "type": "number"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "values": {
      -        "items": {
      -          "anyOf": [
      -            {
      -              "type": "number"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ]
      -        },
      -        "type": "array"
      -      },
      -      "variance": {
      -        "description": "mini_table écart columns (axis=branches)",
      -        "properties": {
      -          "abs": {
      -            "type": "boolean"
      -          },
      -          "color": {
      -            "type": "boolean"
      -          },
      -          "pct": {
      -            "type": "boolean"
      -          }
      -        },
      -        "type": "object"
      -      }
      -    },
      -    "required": [
      -      "role",
      -      "name",
      -      "op"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "from_uid": {
      -        "description": "Existing item UID to replace atomically (section/dashboard unsupported)",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "new_item": {
      -        "description": "Inline payload describing the replacement item",
      -        "properties": {
      -          "aggregation": {
      -            "enum": [
      -              "sum",
      -              "average",
      -              "stock",
      -              "first"
      -            ],
      -            "type": "string"
      -          },
      -          "axis": {
      -            "description": "mini_table column axis: 'time' (periods, default), 'branches', or 'list' (list entries + Total)",
      -            "enum": [
      -              "time",
      -              "branches",
      -              "list"
      -            ],
      -            "type": "string"
      -          },
      -          "branches": {
      -            "description": "mini_table compared branch ids (axis=branches); first = écart base",
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "bridge_config": {
      -            "properties": {
      -              "axis": {
      -                "description": "Bridge dimension: 'time' (default, delta start→end period) or 'branches' (gap between two branches at one period — budget vs actual waterfall).",
      -                "enum": [
      -                  "time",
      -                  "branches"
      -                ],
      -                "type": "string"
      -              },
      -              "branches": {
      -                "description": "Branch ids compared when axis=branches: [from, to].",
      -                "items": {
      -                  "minLength": 1,
      -                  "type": "string"
      -                },
      -                "type": "array"
      -              },
      -              "contributions": {
      -                "items": {
      -                  "minLength": 1,
      -                  "type": "string"
      -                },
      -                "type": "array"
      -              },
      -              "end_period": {
      -                "maxLength": 50,
      -                "type": "string"
      -              },
      -              "endpoint": {
      -                "description": "Single endpoint item (stock/balance) read at start & end periods",
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "endpoint_branch": {
      -                "description": "Read endpoint + contributions under this branch basis (axis=time only).",
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "residual_label": {
      -                "maxLength": 200,
      -                "type": "string"
      -              },
      -              "start_period": {
      -                "maxLength": 50,
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "endpoint"
      -            ],
      -            "type": "object"
      -          },
      -          "by_branch": {
      -            "description": "Chart only: plot one styled series per branch instead of the checked-out view.",
      -            "type": "boolean"
      -          },
      -          "cagr": {
      -            "description": "mini_table (axis=time): show the trailing CAGR column. Default true",
      -            "type": "boolean"
      -          },
      -          "chart_type": {
      -            "enum": [
      -              "line",
      -              "bar",
      -              "area",
      -              "bridge"
      -            ],
      -            "type": "string"
      -          },
      -          "check": {
      -            "description": "Flags the line as a control judged on its own value at every period: a plain amount passes when within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals, so a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (\"Revenue >= 0\") passes when true. Assumption and formula only. Failing periods surface in `layerz_read` under `health`, non-blocking.",
      -            "properties": {
      -              "tolerance": {
      -                "exclusiveMinimum": 0,
      -                "type": "number"
      -              }
      -            },
      -            "type": "object"
      -          },
      -          "collapsed": {
      -            "description": "fold the group by default: a section with children, a Σ aggregator or a list-mode line opens collapsed in the web grid and its rows start hidden under the Excel outline (+/−). false unfolds. View state, outside the blueprint and the diffs",
      -            "type": "boolean"
      -          },
      -          "comment": {
      -            "anyOf": [
      -              {
      -                "maxLength": 2000,
      -                "type": "string"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ],
      -            "description": "Free-form annotation on the item (hypothesis source, rationale, review note)."
      -          },
      -          "compare_to": {
      -            "description": "KPI native comparison: a delta vs another branch (`mode:\"branch\"` + `branch_id`) or a shifted period (`prev_period`/`prev_year`). Rendered as the value plus a signed delta %.",
      -            "properties": {
      -              "branch_id": {
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "display": {
      -                "enum": [
      -                  "abs",
      -                  "pct",
      -                  "both"
      -                ],
      -                "type": "string"
      -              },
      -              "mode": {
      -                "enum": [
      -                  "branch",
      -                  "prev_period",
      -                  "prev_year"
      -                ],
      -                "type": "string"
      -              },
      -              "thresholds": {
      -                "properties": {
      -                  "green": {
      -                    "type": "number"
      -                  },
      -                  "red": {
      -                    "type": "number"
      -                  }
      -                },
      -                "required": [
      -                  "green",
      -                  "red"
      -                ],
      -                "type": "object"
      -              }
      -            },
      -            "required": [
      -              "mode"
      -            ],
      -            "type": "object"
      -          },
      -          "default_branch": {
      -            "description": "Dashboard-only: branch checked out when this dashboard opens; overrides the model default.",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "format": {
      -            "description": "Number format name. Pre-installed: default, decimal_2, decimal_neg, integer, multiple, percent, percent_neg, percent_2, date_dmy, date_dmmmyy, date_mmmyy, date_dmmm (+ the magic `date`, and `currency`/`currency_2` — resolved live from the FINANCE.md `currency` code: `$1,234` for USD, `1 234 €` for EUR). Custom names refer to entries in model.formats — add one with the `meta` op `formats` field (same batch OK); the excel_format follows Excel / Google Sheets, bracket colours and conditions included (`[Green]0;[Red](0);-` paints negatives red on the web and in Excel). An unknown name is rejected with code UNKNOWN_FORMAT listing what is available (`percent` is the current name of the legacy `\"%\"`). Full catalog with each excel_format and rendered positive/negative/zero examples (`default` = dash-for-zero accounting style, `integer` = plain 0): MCP resource `format-spec://reference`.",
      -            "maxLength": 50,
      -            "type": "string"
      -          },
      -          "formula": {
      -            "maxLength": 2000,
      -            "type": "string"
      -          },
      -          "inputs": {
      -            "description": "Inputs override of a `formula` item (item UIDs or same-batch temp ids), derived from the expression when omitted. Ignored on every other role: a `balance` takes its flows from its children, an aggregator sums them.",
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "item_style": {
      -            "enum": [
      -              "normal",
      -              "subtotal",
      -              "total",
      -              "kpi"
      -            ],
      -            "type": "string"
      -          },
      -          "list_mode": {
      -            "description": "Chart only: how a list-backed series renders — 'split' (default) plots one series per list element, 'total' plots the item's aggregate as one series (a list total charted without a mirror formula).",
      -            "enum": [
      -              "split",
      -              "total"
      -            ],
      -            "type": "string"
      -          },
      -          "list_total": {
      -            "description": "List-mode only: show the list's total (aggregate row values). Default off; the total is forced ON while any formula/callup/parent/widget reads the aggregate.",
      -            "type": "boolean"
      -          },
      -          "liste": {
      -            "description": "mini_table list whose entries become the columns (axis=list)",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "liste_ref": {
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "monitor": {
      -            "description": "Deprecated (MDK 0.13.0) — use `check`. A canonical assert (\"ABS(value) < t\", \"== 0\") is converted; any other rule is rejected: put it in the line's formula and set `check: {}`.",
      -            "properties": {
      -              "assert": {
      -                "maxLength": 200,
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "label": {
      -                "maxLength": 200,
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "assert"
      -            ],
      -            "type": "object"
      -          },
      -          "name": {
      -            "description": "Display name",
      -            "maxLength": 200,
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "opening_balance": {
      -            "type": "number"
      -          },
      -          "period_mode": {
      -            "description": "kpi / mini_table period mode. 'ytd' shows the year to date: the cumulative from January through the target period (each column for a time-axis mini_table). Flows are summed, an `average` line averaged, a `stock` line read at the period, and a ratio line (formula `a / b`) recomputed on the cumulated operands. Branch columns, écarts and the KPI comparison follow (prev_year = year to date of the same month a year earlier). Default 'period'.",
      -            "enum": [
      -              "period",
      -              "ytd"
      -            ],
      -            "type": "string"
      -          },
      -          "period_window": {
      -            "anyOf": [
      -              {
      -                "properties": {
      -                  "end": {
      -                    "maxLength": 20,
      -                    "type": "string"
      -                  },
      -                  "fit": {
      -                    "enum": [
      -                      "data",
      -                      "full"
      -                    ],
      -                    "type": "string"
      -                  },
      -                  "start": {
      -                    "maxLength": 20,
      -                    "type": "string"
      -                  }
      -                },
      -                "type": "object"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ],
      -            "description": "Display period window of a chart / kpi sparkline / time mini_table. `start`/`end` are period labels at the widget's grain (bounds independent — either alone is valid); `fit` governs the unset bounds: 'data' (the default, absent field included) auto-fits to the periods actually carrying data and follows imports, 'full' spans the whole timeline. `null` clears it (back to fit-to-data)."
      -          },
      -          "position": {
      -            "anyOf": [
      -              {
      -                "properties": {
      -                  "col": {
      -                    "maximum": 11,
      -                    "minimum": 0,
      -                    "type": "integer"
      -                  },
      -                  "row": {
      -                    "maximum": 400,
      -                    "minimum": 0,
      -                    "type": "integer"
      -                  }
      -                },
      -                "required": [
      -                  "col",
      -                  "row"
      -                ],
      -                "type": "object"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ],
      -            "description": "dashboard-child pinned grid origin {col 0–11, row ≥ 0}: the widget sits at these cells (pushed down when it collides with an earlier pinned widget). Absent = flow placement (first-fit dense in sort order — a new widget fills the topmost free hole); null clears the pin. The web canvas pins every widget on the first drag"
      -          },
      -          "role": {
      -            "description": "Role of the item. assumption: a typed input (value / values / timeline_values), the only role a branch overlays. formula: a computed transformation (formula). formula with no expression and children: an aggregator that sums its children (a subtotal value; a nested section is structural grouping with no value). callup: a typed mirror of one source whose value flows into its parent (source): balance flows, a value surfaced in a section or subtotal; a formula references its source directly instead. balance: a rolling stock (opening_balance) that sums its callup-child flows. section: structural container, no value. dashboard / chart / kpi / mini_table: presentational. A formula carrying both an expression and children is rejected (FORMULA_EXPR_AND_CHILDREN). A single bare reference written as a formula is auto-posed as a callup mirror, unless it pins a `timeline_ref` or an `aggregation` different from its source (then it stays a formula).",
      -            "enum": [
      -              "assumption",
      -              "formula",
      -              "callup",
      -              "balance",
      -              "section",
      -              "chart",
      -              "dashboard",
      -              "kpi",
      -              "mini_table"
      -            ],
      -            "type": "string"
      -          },
      -          "row_break": {
      -            "description": "dashboard-child line break (flow widgets only): start this widget on a fresh grid row. Inert once the widget has a position",
      -            "type": "boolean"
      -          },
      -          "row_styles": {
      -            "additionalProperties": {
      -              "enum": [
      -                "normal",
      -                "subtotal",
      -                "total",
      -                "kpi"
      -              ],
      -              "type": "string"
      -            },
      -            "description": "mini_table per-row style override { <row UID / temp ID>: 'normal' | 'subtotal' | 'total' | 'kpi' }; an absent key keeps the row item's own style, a key outside `rows` is dropped, {} clears every override",
      -            "propertyNames": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "object"
      -          },
      -          "rows": {
      -            "description": "mini_table curated row item UIDs / temp IDs / names",
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "series": {
      -            "items": {
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "type": "array"
      -          },
      -          "series_defs": {
      -            "description": "Per-series branch: supersedes `series`. Each entry plots one item under a specific branch (e.g. Revenue@budget vs Revenue@actuals). `uid` accepts a temp id.",
      -            "items": {
      -              "properties": {
      -                "branch_id": {
      -                  "minLength": 1,
      -                  "type": "string"
      -                },
      -                "uid": {
      -                  "minLength": 1,
      -                  "type": "string"
      -                }
      -              },
      -              "required": [
      -                "uid"
      -              ],
      -              "type": "object"
      -            },
      -            "type": "array"
      -          },
      -          "source": {
      -            "description": "Callup source UID or temp ID",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "span": {
      -            "description": "dashboard-child grid footprint (chart/kpi/mini_table): cols on the 12-column grid × 140-px row units. Defaults: kpi 3×1, chart/mini_table 6×2",
      -            "properties": {
      -              "cols": {
      -                "maximum": 12,
      -                "minimum": 1,
      -                "type": "integer"
      -              },
      -              "rows": {
      -                "maximum": 4,
      -                "minimum": 1,
      -                "type": "integer"
      -              }
      -            },
      -            "type": "object"
      -          },
      -          "sparkline": {
      -            "description": "KPI trend mini-chart under the value.",
      -            "type": "boolean"
      -          },
      -          "target": {
      -            "description": "KPI/mini_table target UID or temp ID",
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          "target_period": {
      -            "maxLength": 50,
      -            "type": "string"
      -          },
      -          "timeline_ref": {
      -            "enum": [
      -              "constant",
      -              "monthly",
      -              "yearly",
      -              "quarterly"
      -            ],
      -            "type": "string"
      -          },
      -          "timeline_values": {
      -            "additionalProperties": {
      -              "anyOf": [
      -                {
      -                  "anyOf": [
      -                    {
      -                      "type": "number"
      -                    },
      -                    {
      -                      "type": "null"
      -                    }
      -                  ]
      -                },
      -                {
      -                  "items": {
      -                    "anyOf": [
      -                      {
      -                        "type": "number"
      -                      },
      -                      {
      -                        "type": "null"
      -                      }
      -                    ]
      -                  },
      -                  "type": "array"
      -                }
      -              ]
      -            },
      -            "description": "Periodic values, keyed by context. List-mode item: one series per list entry, keyed by the element UID, label, or a `list_create` temp id of the same batch (a temp id is scoped to the batch that declares it; later batches key by label or UID). On `update` the map merges element by element: entries it does not name keep their series (send `[]` to clear one); on `create` / `replace` it is the full set. Non-list item: a sparse per-period patch keyed by period id (`{\"2026-06\": -119.19}`, keys YYYY / YYYY-MM / YYYY-Qn) that rewrites the named cells of the typed `values` series and leaves the rest intact; a full series keyed by a canonical grain (`monthly` / `quarterly` / `yearly` / `constant`) is import-owned and rejected here. A single number is coerced to a 1-element array. List cells left unset read as 0 (no forward-fill).",
      -            "propertyNames": {
      -              "type": "string"
      -            },
      -            "type": "object"
      -          },
      -          "unit": {
      -            "description": "mini_table amount scaling: 'none' (default), 'k' (thousands), 'm' (millions), 'auto' (per-table scale); %, multiples and dates are not divided",
      -            "enum": [
      -              "none",
      -              "k",
      -              "m",
      -              "auto"
      -            ],
      -            "type": "string"
      -          },
      -          "value": {
      -            "anyOf": [
      -              {
      -                "type": "number"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ]
      -          },
      -          "values": {
      -            "items": {
      -              "anyOf": [
      -                {
      -                  "type": "number"
      -                },
      -                {
      -                  "type": "null"
      -                }
      -              ]
      -            },
      -            "type": "array"
      -          },
      -          "variance": {
      -            "description": "mini_table écart columns (axis=branches)",
      -            "properties": {
      -              "abs": {
      -                "type": "boolean"
      -              },
      -              "color": {
      -                "type": "boolean"
      -              },
      -              "pct": {
      -                "type": "boolean"
      -              }
      -            },
      -            "type": "object"
      -          }
      -        },
      -        "required": [
      -          "role",
      -          "name"
      -        ],
      -        "type": "object"
      -      },
      -      "op": {
      -        "const": "replace",
      -        "type": "string"
      -      },
      -      "preserve_order": {
      -        "type": "boolean"
      -      },
      -      "preserve_parent": {
      -        "type": "boolean"
      -      },
      -      "preserve_presentation": {
      -        "description": "Default true: every presentation / annotation field `new_item` omits (item_style, format, comment, check, span, position, period_window, compare_to, sparkline, series_defs, …) is carried over from the replaced item when the new role can hold it; `false` rebuilds the item from `new_item` alone.",
      -        "type": "boolean"
      -      },
      -      "preserve_style": {
      -        "type": "boolean"
      -      }
      -    },
      -    "required": [
      -      "op",
      -      "from_uid",
      -      "new_item"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "op": {
      -        "const": "delete",
      -        "type": "string"
      -      },
      -      "uid": {
      -        "description": "UID of item to delete",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "op",
      -      "uid"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "after": {
      -        "description": "UID of item to place after (for ordering)",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "op": {
      -        "const": "move",
      -        "type": "string"
      -      },
      -      "parent": {
      -        "description": "New parent UID",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "uid": {
      -        "description": "UID of item to move",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "op",
      -      "uid"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "id": {
      -        "description": "Temp ID for intra-batch references — other create ops in the same batch can pass this value as their `liste_ref` so a list and its consumers can ship in one patch (e.g. set `id: \"_emp\"` on `list_create`, then `liste_ref: \"_emp\"` on an assumption created in the same batch).",
      -        "maxLength": 32,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "items": {
      -        "items": {
      -          "properties": {
      -            "id": {
      -              "maxLength": 32,
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "label": {
      -              "maxLength": 200,
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "mapped_to": {
      -              "additionalProperties": {
      -                "items": {
      -                  "type": "string"
      -                },
      -                "type": "array"
      -              },
      -              "propertyNames": {
      -                "type": "string"
      -              },
      -              "type": "object"
      -            },
      -            "uid": {
      -              "minLength": 1,
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "label"
      -          ],
      -          "type": "object"
      -        },
      -        "maxItems": 500,
      -        "type": "array"
      -      },
      -      "name": {
      -        "maxLength": 200,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "op": {
      -        "const": "list_create",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "op",
      -      "name"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "items": {
      -        "items": {
      -          "properties": {
      -            "id": {
      -              "maxLength": 32,
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "label": {
      -              "maxLength": 200,
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "mapped_to": {
      -              "additionalProperties": {
      -                "items": {
      -                  "type": "string"
      -                },
      -                "type": "array"
      -              },
      -              "propertyNames": {
      -                "type": "string"
      -              },
      -              "type": "object"
      -            },
      -            "uid": {
      -              "minLength": 1,
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "label"
      -          ],
      -          "type": "object"
      -        },
      -        "maxItems": 500,
      -        "type": "array"
      -      },
      -      "name": {
      -        "maxLength": 200,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "op": {
      -        "const": "list_update",
      -        "type": "string"
      -      },
      -      "uid": {
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "op",
      -      "uid"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "op": {
      -        "const": "list_delete",
      -        "type": "string"
      -      },
      -      "uid": {
      -        "description": "UID of list to delete",
      -        "minLength": 1,
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "op",
      -      "uid"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "properties": {
      -      "default_branch": {
      -        "anyOf": [
      -          {
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "finance_md": {
      -        "anyOf": [
      -          {
      -            "maxLength": 5000,
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "formats": {
      -        "additionalProperties": {
      -          "properties": {
      -            "display_name": {
      -              "maxLength": 80,
      -              "type": "string"
      -            },
      -            "excel_format": {
      -              "maxLength": 120,
      -              "minLength": 1,
      -              "type": "string"
      -            },
      -            "name": {
      -              "maxLength": 50,
      -              "minLength": 1,
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "name",
      -            "excel_format"
      -          ],
      -          "type": "object"
      -        },
      -        "propertyNames": {
      -          "maxLength": 50,
      -          "minLength": 1,
      -          "type": "string"
      -        },
      -        "type": "object"
      -      },
      -      "glyph": {
      -        "anyOf": [
      -          {
      -            "maxLength": 60,
      -            "minLength": 1,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Model emblem icon: a kebab-case Lucide icon name (https://lucide.dev/icons), e.g. \"trending-up\", \"coffee\", \"landmark\", \"rocket\", \"house\", \"users\". Shown in-app and on the social/OG card. Emojis and free text are rejected with suggestions. Aliases normalized: cash/money→banknote, bank→landmark, cart→shopping-cart, chart/graph→chart-line. `null` clears it (falls back to a monogram of the model name)."
      -      },
      -      "name": {
      -        "maxLength": 100,
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "number_locale": {
      -        "anyOf": [
      -          {
      -            "enum": [
      -              "en",
      -              "fr",
      -              "de"
      -            ],
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "op": {
      -        "const": "meta",
      -        "type": "string"
      -      },
      -      "subtitle": {
      -        "anyOf": [
      -          {
      -            "maxLength": 160,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "timelines": {
      -        "properties": {
      -          "monthly": {
      -            "anyOf": [
      -              {
      -                "properties": {
      -                  "end": {
      -                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -                    "type": "string"
      -                  },
      -                  "start": {
      -                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -                    "type": "string"
      -                  }
      -                },
      -                "required": [
      -                  "start",
      -                  "end"
      -                ],
      -                "type": "object"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ]
      -          },
      -          "quarterly": {
      -            "anyOf": [
      -              {
      -                "properties": {
      -                  "end": {
      -                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -                    "type": "string"
      -                  },
      -                  "start": {
      -                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -                    "type": "string"
      -                  }
      -                },
      -                "required": [
      -                  "start",
      -                  "end"
      -                ],
      -                "type": "object"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ]
      -          },
      -          "yearly": {
      -            "anyOf": [
      -              {
      -                "properties": {
      -                  "end": {
      -                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -                    "type": "string"
      -                  },
      -                  "start": {
      -                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -                    "type": "string"
      -                  }
      -                },
      -                "required": [
      -                  "start",
      -                  "end"
      -                ],
      -                "type": "object"
      -              },
      -              {
      -                "type": "null"
      -              }
      -            ]
      -          }
      -        },
      -        "type": "object"
      -      }
      -    },
      -    "required": [
      -      "op"
      -    ],
      -    "type": "object"
      -  }
      -]
    • addedInput schema / properties / ops / items / propertyNames
      Added value: +{
      +  "type": "string"
      +}
    • addedInput schema / properties / ops / items / type
      Added value: +"object"
    • removedInput schema / properties / ops / minItems
      Removed value: -1
  2. Changed1 schema field changed
    • addedInput schema / properties / ops
      Added value: +{
      +  "description": "`layerz_patch` operations applied on this branch in the same call.",
      +  "items": {
      +    "oneOf": [
      +      {
      +        "properties": {
      +          "aggregation": {
      +            "enum": [
      +              "sum",
      +              "average",
      +              "stock",
      +              "first"
      +            ],
      +            "type": "string"
      +          },
      +          "axis": {
      +            "description": "mini_table column axis: 'time' (periods, default), 'branches', or 'list' (list entries + Total)",
      +            "enum": [
      +              "time",
      +              "branches",
      +              "list"
      +            ],
      +            "type": "string"
      +          },
      +          "branches": {
      +            "description": "mini_table compared branch ids (axis=branches); first = écart base",
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "bridge_config": {
      +            "properties": {
      +              "axis": {
      +                "description": "Bridge dimension: 'time' (default, delta start→end period) or 'branches' (gap between two branches at one period — budget vs actual waterfall).",
      +                "enum": [
      +                  "time",
      +                  "branches"
      +                ],
      +                "type": "string"
      +              },
      +              "branches": {
      +                "description": "Branch ids compared when axis=branches: [from, to].",
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "contributions": {
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "end_period": {
      +                "maxLength": 50,
      +                "type": "string"
      +              },
      +              "endpoint": {
      +                "description": "Single endpoint item (stock/balance) read at start & end periods",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "endpoint_branch": {
      +                "description": "Read endpoint + contributions under this branch basis (axis=time only).",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "residual_label": {
      +                "maxLength": 200,
      +                "type": "string"
      +              },
      +              "start_period": {
      +                "maxLength": 50,
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "endpoint"
      +            ],
      +            "type": "object"
      +          },
      +          "by_branch": {
      +            "description": "Chart only: one styled series per branch; false reverts to the checked-out view.",
      +            "type": "boolean"
      +          },
      +          "cagr": {
      +            "description": "mini_table (axis=time): show the trailing CAGR column. Default true",
      +            "type": "boolean"
      +          },
      +          "chart_type": {
      +            "enum": [
      +              "line",
      +              "bar",
      +              "area",
      +              "bridge"
      +            ],
      +            "type": "string"
      +          },
      +          "check": {
      +            "anyOf": [
      +              {
      +                "properties": {
      +                  "tolerance": {
      +                    "exclusiveMinimum": 0,
      +                    "type": "number"
      +                  }
      +                },
      +                "type": "object"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Flags the line as a control judged on its own value: a plain amount passes when within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals); a formula that is itself a comparison / AND / OR / NOT passes when true. `null` removes the check. Failing periods surface in `layerz_read` under `health`, non-blocking."
      +          },
      +          "collapsed": {
      +            "description": "fold the group by default: a section with children, a Σ aggregator or a list-mode line opens collapsed in the web grid and its rows start hidden under the Excel outline (+/−). false unfolds. View state, outside the blueprint and the diffs",
      +            "type": "boolean"
      +          },
      +          "comment": {
      +            "anyOf": [
      +              {
      +                "maxLength": 2000,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Free-form annotation on the item (null clears it)."
      +          },
      +          "compare_to": {
      +            "anyOf": [
      +              {
      +                "properties": {
      +                  "branch_id": {
      +                    "minLength": 1,
      +                    "type": "string"
      +                  },
      +                  "display": {
      +                    "enum": [
      +                      "abs",
      +                      "pct",
      +                      "both"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  "mode": {
      +                    "enum": [
      +                      "branch",
      +                      "prev_period",
      +                      "prev_year"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  "thresholds": {
      +                    "properties": {
      +                      "green": {
      +                        "type": "number"
      +                      },
      +                      "red": {
      +                        "type": "number"
      +                      }
      +                    },
      +                    "required": [
      +                      "green",
      +                      "red"
      +                    ],
      +                    "type": "object"
      +                  }
      +                },
      +                "required": [
      +                  "mode"
      +                ],
      +                "type": "object"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "KPI native comparison; null clears it."
      +          },
      +          "default_branch": {
      +            "anyOf": [
      +              {
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Dashboard-only: branch checked out when this dashboard opens; null clears it."
      +          },
      +          "format": {
      +            "description": "Number format name. Pre-installed: default, decimal_2, decimal_neg, integer, multiple, percent, percent_neg, percent_2, date_dmy, date_dmmmyy, date_mmmyy, date_dmmm (+ the magic `date`, and `currency`/`currency_2` — resolved live from the FINANCE.md `currency` code: `$1,234` for USD, `1 234 €` for EUR). Custom names refer to entries in model.formats — add one with the `meta` op `formats` field (same batch OK); the excel_format follows Excel / Google Sheets, bracket colours and conditions included (`[Green]0;[Red](0);-` paints negatives red on the web and in Excel). An unknown name is rejected with code UNKNOWN_FORMAT listing what is available (`percent` is the current name of the legacy `\"%\"`). Full catalog with each excel_format and rendered positive/negative/zero examples (`default` = dash-for-zero accounting style, `integer` = plain 0): MCP resource `format-spec://reference`.",
      +            "maxLength": 50,
      +            "type": "string"
      +          },
      +          "formula": {
      +            "maxLength": 2000,
      +            "type": "string"
      +          },
      +          "inputs": {
      +            "description": "Inputs override of a `formula` item (item UIDs or same-batch temp ids), derived from the expression when omitted. Ignored on every other role: a `balance` takes its flows from its children, an aggregator sums them.",
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "item_style": {
      +            "enum": [
      +              "normal",
      +              "subtotal",
      +              "total",
      +              "kpi"
      +            ],
      +            "type": "string"
      +          },
      +          "list_mode": {
      +            "description": "Chart only: 'split' (default) = one series per list element, 'total' = the list-backed item's aggregate as one series.",
      +            "enum": [
      +              "split",
      +              "total"
      +            ],
      +            "type": "string"
      +          },
      +          "list_total": {
      +            "description": "List-mode only: show the list's total (aggregate row values). Default off; forced ON while the aggregate is referenced.",
      +            "type": "boolean"
      +          },
      +          "liste": {
      +            "description": "mini_table list whose entries become the columns (axis=list)",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "liste_ref": {
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "monitor": {
      +            "anyOf": [
      +              {
      +                "properties": {
      +                  "assert": {
      +                    "maxLength": 200,
      +                    "minLength": 1,
      +                    "type": "string"
      +                  },
      +                  "label": {
      +                    "maxLength": 200,
      +                    "type": "string"
      +                  }
      +                },
      +                "required": [
      +                  "assert"
      +                ],
      +                "type": "object"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Deprecated (MDK 0.13.0) — use `check`. A canonical assert is converted, any other rule is rejected; `null` removes the check."
      +          },
      +          "name": {
      +            "description": "New display label (also the formula identifier)",
      +            "maxLength": 200,
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "op": {
      +            "const": "update",
      +            "type": "string"
      +          },
      +          "opening_balance": {
      +            "type": "number"
      +          },
      +          "parent": {
      +            "anyOf": [
      +              {
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "New parent UID (null to move to root)"
      +          },
      +          "period_mode": {
      +            "description": "kpi / mini_table period mode. 'ytd' shows the year to date: the cumulative from January through the target period (each column for a time-axis mini_table). Flows are summed, an `average` line averaged, a `stock` line read at the period, and a ratio line (formula `a / b`) recomputed on the cumulated operands. Branch columns, écarts and the KPI comparison follow (prev_year = year to date of the same month a year earlier). Default 'period'.",
      +            "enum": [
      +              "period",
      +              "ytd"
      +            ],
      +            "type": "string"
      +          },
      +          "period_window": {
      +            "anyOf": [
      +              {
      +                "properties": {
      +                  "end": {
      +                    "maxLength": 20,
      +                    "type": "string"
      +                  },
      +                  "fit": {
      +                    "enum": [
      +                      "data",
      +                      "full"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  "start": {
      +                    "maxLength": 20,
      +                    "type": "string"
      +                  }
      +                },
      +                "type": "object"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Display period window of a chart / kpi sparkline / time mini_table. `start`/`end` are period labels at the widget's grain (bounds independent — either alone is valid); `fit` governs the unset bounds: 'data' (the default, absent field included) auto-fits to the periods actually carrying data and follows imports, 'full' spans the whole timeline. `null` clears it (back to fit-to-data)."
      +          },
      +          "position": {
      +            "anyOf": [
      +              {
      +                "properties": {
      +                  "col": {
      +                    "maximum": 11,
      +                    "minimum": 0,
      +                    "type": "integer"
      +                  },
      +                  "row": {
      +                    "maximum": 400,
      +                    "minimum": 0,
      +                    "type": "integer"
      +                  }
      +                },
      +                "required": [
      +                  "col",
      +                  "row"
      +                ],
      +                "type": "object"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "dashboard-child pinned grid origin {col 0–11, row ≥ 0}: the widget sits at these cells (pushed down when it collides with an earlier pinned widget). Absent = flow placement (first-fit dense in sort order — a new widget fills the topmost free hole); null clears the pin. The web canvas pins every widget on the first drag"
      +          },
      +          "role": {
      +            "description": "Change the item role. Role of the item. assumption: a typed input (value / values / timeline_values), the only role a branch overlays. formula: a computed transformation (formula). formula with no expression and children: an aggregator that sums its children (a subtotal value; a nested section is structural grouping with no value). callup: a typed mirror of one source whose value flows into its parent (source): balance flows, a value surfaced in a section or subtotal; a formula references its source directly instead. balance: a rolling stock (opening_balance) that sums its callup-child flows. section: structural container, no value. dashboard / chart / kpi / mini_table: presentational. A formula carrying both an expression and children is rejected (FORMULA_EXPR_AND_CHILDREN). A single bare reference written as a formula is auto-posed as a callup mirror, unless it pins a `timeline_ref` or an `aggregation` different from its source (then it stays a formula).",
      +            "enum": [
      +              "assumption",
      +              "formula",
      +              "callup",
      +              "balance",
      +              "section",
      +              "chart",
      +              "dashboard",
      +              "kpi",
      +              "mini_table"
      +            ],
      +            "type": "string"
      +          },
      +          "row_break": {
      +            "description": "dashboard-child line break (flow widgets only): start this widget on a fresh grid row. Inert once the widget has a position",
      +            "type": "boolean"
      +          },
      +          "row_styles": {
      +            "additionalProperties": {
      +              "enum": [
      +                "normal",
      +                "subtotal",
      +                "total",
      +                "kpi"
      +              ],
      +              "type": "string"
      +            },
      +            "description": "mini_table per-row style override { <row UID / temp ID>: 'normal' | 'subtotal' | 'total' | 'kpi' }; an absent key keeps the row item's own style, a key outside `rows` is dropped, {} clears every override",
      +            "propertyNames": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "object"
      +          },
      +          "rows": {
      +            "description": "mini_table curated row item UIDs / temp IDs / names",
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "series": {
      +            "description": "Chart series UIDs",
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "series_defs": {
      +            "description": "Per-series branch; supersedes `series`.",
      +            "items": {
      +              "properties": {
      +                "branch_id": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "uid": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "uid"
      +              ],
      +              "type": "object"
      +            },
      +            "type": "array"
      +          },
      +          "source": {
      +            "description": "Callup source UID",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "span": {
      +            "description": "dashboard-child grid footprint (chart/kpi/mini_table): cols on the 12-column grid × 140-px row units. Defaults: kpi 3×1, chart/mini_table 6×2",
      +            "properties": {
      +              "cols": {
      +                "maximum": 12,
      +                "minimum": 1,
      +                "type": "integer"
      +              },
      +              "rows": {
      +                "maximum": 4,
      +                "minimum": 1,
      +                "type": "integer"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "sparkline": {
      +            "description": "KPI trend mini-chart.",
      +            "type": "boolean"
      +          },
      +          "target": {
      +            "description": "KPI/mini_table target UID",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "target_period": {
      +            "maxLength": 50,
      +            "type": "string"
      +          },
      +          "timeline_ref": {
      +            "enum": [
      +              "constant",
      +              "monthly",
      +              "yearly",
      +              "quarterly"
      +            ],
      +            "type": "string"
      +          },
      +          "timeline_values": {
      +            "additionalProperties": {
      +              "anyOf": [
      +                {
      +                  "anyOf": [
      +                    {
      +                      "type": "number"
      +                    },
      +                    {
      +                      "type": "null"
      +                    }
      +                  ]
      +                },
      +                {
      +                  "items": {
      +                    "anyOf": [
      +                      {
      +                        "type": "number"
      +                      },
      +                      {
      +                        "type": "null"
      +                      }
      +                    ]
      +                  },
      +                  "type": "array"
      +                }
      +              ]
      +            },
      +            "description": "Periodic values, keyed by context. List-mode item: one series per list entry, keyed by the element UID, label, or a `list_create` temp id of the same batch (a temp id is scoped to the batch that declares it; later batches key by label or UID). On `update` the map merges element by element: entries it does not name keep their series (send `[]` to clear one); on `create` / `replace` it is the full set. Non-list item: a sparse per-period patch keyed by period id (`{\"2026-06\": -119.19}`, keys YYYY / YYYY-MM / YYYY-Qn) that rewrites the named cells of the typed `values` series and leaves the rest intact; a full series keyed by a canonical grain (`monthly` / `quarterly` / `yearly` / `constant`) is import-owned and rejected here. A single number is coerced to a 1-element array. List cells left unset read as 0 (no forward-fill).",
      +            "propertyNames": {
      +              "type": "string"
      +            },
      +            "type": "object"
      +          },
      +          "uid": {
      +            "description": "Existing item UID to update",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "unit": {
      +            "description": "mini_table amount scaling: 'none' (default), 'k' (thousands), 'm' (millions), 'auto' (per-table scale); %, multiples and dates are not divided",
      +            "enum": [
      +              "none",
      +              "k",
      +              "m",
      +              "auto"
      +            ],
      +            "type": "string"
      +          },
      +          "value": {
      +            "anyOf": [
      +              {
      +                "type": "number"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ]
      +          },
      +          "values": {
      +            "items": {
      +              "anyOf": [
      +                {
      +                  "type": "number"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ]
      +            },
      +            "type": "array"
      +          },
      +          "variance": {
      +            "description": "mini_table écart columns (axis=branches)",
      +            "properties": {
      +              "abs": {
      +                "type": "boolean"
      +              },
      +              "color": {
      +                "type": "boolean"
      +              },
      +              "pct": {
      +                "type": "boolean"
      +              }
      +            },
      +            "type": "object"
      +          }
      +        },
      +        "required": [
      +          "op",
      +          "uid"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "aggregation": {
      +            "enum": [
      +              "sum",
      +              "average",
      +              "stock",
      +              "first"
      +            ],
      +            "type": "string"
      +          },
      +          "axis": {
      +            "description": "mini_table column axis: 'time' (periods, default), 'branches', or 'list' (list entries + Total)",
      +            "enum": [
      +              "time",
      +              "branches",
      +              "list"
      +            ],
      +            "type": "string"
      +          },
      +          "branches": {
      +            "description": "mini_table compared branch ids (axis=branches); first = écart base",
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "bridge_config": {
      +            "properties": {
      +              "axis": {
      +                "description": "Bridge dimension: 'time' (default, delta start→end period) or 'branches' (gap between two branches at one period — budget vs actual waterfall).",
      +                "enum": [
      +                  "time",
      +                  "branches"
      +                ],
      +                "type": "string"
      +              },
      +              "branches": {
      +                "description": "Branch ids compared when axis=branches: [from, to].",
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "contributions": {
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "end_period": {
      +                "maxLength": 50,
      +                "type": "string"
      +              },
      +              "endpoint": {
      +                "description": "Single endpoint item (stock/balance) read at start & end periods",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "endpoint_branch": {
      +                "description": "Read endpoint + contributions under this branch basis (axis=time only).",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "residual_label": {
      +                "maxLength": 200,
      +                "type": "string"
      +              },
      +              "start_period": {
      +                "maxLength": 50,
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "endpoint"
      +            ],
      +            "type": "object"
      +          },
      +          "by_branch": {
      +            "description": "Chart only: plot one styled series per branch instead of the checked-out view.",
      +            "type": "boolean"
      +          },
      +          "cagr": {
      +            "description": "mini_table (axis=time): show the trailing CAGR column. Default true",
      +            "type": "boolean"
      +          },
      +          "chart_type": {
      +            "enum": [
      +              "line",
      +              "bar",
      +              "area",
      +              "bridge"
      +            ],
      +            "type": "string"
      +          },
      +          "check": {
      +            "description": "Flags the line as a control judged on its own value at every period: a plain amount passes when within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals, so a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (\"Revenue >= 0\") passes when true. Assumption and formula only. Failing periods surface in `layerz_read` under `health`, non-blocking.",
      +            "properties": {
      +              "tolerance": {
      +                "exclusiveMinimum": 0,
      +                "type": "number"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "collapsed": {
      +            "description": "fold the group by default: a section with children, a Σ aggregator or a list-mode line opens collapsed in the web grid and its rows start hidden under the Excel outline (+/−). false unfolds. View state, outside the blueprint and the diffs",
      +            "type": "boolean"
      +          },
      +          "comment": {
      +            "anyOf": [
      +              {
      +                "maxLength": 2000,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Free-form annotation on the item (hypothesis source, rationale, review note)."
      +          },
      +          "compare_to": {
      +            "description": "KPI native comparison: a delta vs another branch (`mode:\"branch\"` + `branch_id`) or a shifted period (`prev_period`/`prev_year`). Rendered as the value plus a signed delta %.",
      +            "properties": {
      +              "branch_id": {
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "display": {
      +                "enum": [
      +                  "abs",
      +                  "pct",
      +                  "both"
      +                ],
      +                "type": "string"
      +              },
      +              "mode": {
      +                "enum": [
      +                  "branch",
      +                  "prev_period",
      +                  "prev_year"
      +                ],
      +                "type": "string"
      +              },
      +              "thresholds": {
      +                "properties": {
      +                  "green": {
      +                    "type": "number"
      +                  },
      +                  "red": {
      +                    "type": "number"
      +                  }
      +                },
      +                "required": [
      +                  "green",
      +                  "red"
      +                ],
      +                "type": "object"
      +              }
      +            },
      +            "required": [
      +              "mode"
      +            ],
      +            "type": "object"
      +          },
      +          "default_branch": {
      +            "description": "Dashboard-only: branch checked out when this dashboard opens; overrides the model default.",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "format": {
      +            "description": "Number format name. Pre-installed: default, decimal_2, decimal_neg, integer, multiple, percent, percent_neg, percent_2, date_dmy, date_dmmmyy, date_mmmyy, date_dmmm (+ the magic `date`, and `currency`/`currency_2` — resolved live from the FINANCE.md `currency` code: `$1,234` for USD, `1 234 €` for EUR). Custom names refer to entries in model.formats — add one with the `meta` op `formats` field (same batch OK); the excel_format follows Excel / Google Sheets, bracket colours and conditions included (`[Green]0;[Red](0);-` paints negatives red on the web and in Excel). An unknown name is rejected with code UNKNOWN_FORMAT listing what is available (`percent` is the current name of the legacy `\"%\"`). Full catalog with each excel_format and rendered positive/negative/zero examples (`default` = dash-for-zero accounting style, `integer` = plain 0): MCP resource `format-spec://reference`.",
      +            "maxLength": 50,
      +            "type": "string"
      +          },
      +          "formula": {
      +            "maxLength": 2000,
      +            "type": "string"
      +          },
      +          "id": {
      +            "description": "Temp ID for intra-batch references — other create ops in the same batch can use this value as their `parent`, `source`, `target`, or `series` to wire references before the real UID is generated. Numeric (`_1`, `_2`) keeps it short; descriptive (`_starting_customers`) is fine up to 32 chars.",
      +            "maxLength": 32,
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "inputs": {
      +            "description": "Inputs override of a `formula` item (item UIDs or same-batch temp ids), derived from the expression when omitted. Ignored on every other role: a `balance` takes its flows from its children, an aggregator sums them.",
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "item_style": {
      +            "enum": [
      +              "normal",
      +              "subtotal",
      +              "total",
      +              "kpi"
      +            ],
      +            "type": "string"
      +          },
      +          "list_mode": {
      +            "description": "Chart only: how a list-backed series renders — 'split' (default) plots one series per list element, 'total' plots the item's aggregate as one series (a list total charted without a mirror formula).",
      +            "enum": [
      +              "split",
      +              "total"
      +            ],
      +            "type": "string"
      +          },
      +          "list_total": {
      +            "description": "List-mode only: show the list's total (aggregate row values). Default off; the total is forced ON while any formula/callup/parent/widget reads the aggregate.",
      +            "type": "boolean"
      +          },
      +          "liste": {
      +            "description": "mini_table list whose entries become the columns (axis=list)",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "liste_ref": {
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "monitor": {
      +            "description": "Deprecated (MDK 0.13.0) — use `check`. A canonical assert (\"ABS(value) < t\", \"== 0\") is converted; any other rule is rejected: put it in the line's formula and set `check: {}`.",
      +            "properties": {
      +              "assert": {
      +                "maxLength": 200,
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "label": {
      +                "maxLength": 200,
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "assert"
      +            ],
      +            "type": "object"
      +          },
      +          "name": {
      +            "description": "Display name",
      +            "maxLength": 200,
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "op": {
      +            "const": "create",
      +            "type": "string"
      +          },
      +          "opening_balance": {
      +            "type": "number"
      +          },
      +          "parent": {
      +            "description": "Parent container: either an 8-char UID of an existing section/balance/dashboard, or a temp `id` from an earlier create op in the same batch (e.g. set `id: \"_pl\"` on a section create, then `parent: \"_pl\"` on each child item).",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "period_mode": {
      +            "description": "kpi / mini_table period mode. 'ytd' shows the year to date: the cumulative from January through the target period (each column for a time-axis mini_table). Flows are summed, an `average` line averaged, a `stock` line read at the period, and a ratio line (formula `a / b`) recomputed on the cumulated operands. Branch columns, écarts and the KPI comparison follow (prev_year = year to date of the same month a year earlier). Default 'period'.",
      +            "enum": [
      +              "period",
      +              "ytd"
      +            ],
      +            "type": "string"
      +          },
      +          "period_window": {
      +            "anyOf": [
      +              {
      +                "properties": {
      +                  "end": {
      +                    "maxLength": 20,
      +                    "type": "string"
      +                  },
      +                  "fit": {
      +                    "enum": [
      +                      "data",
      +                      "full"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  "start": {
      +                    "maxLength": 20,
      +                    "type": "string"
      +                  }
      +                },
      +                "type": "object"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Display period window of a chart / kpi sparkline / time mini_table. `start`/`end` are period labels at the widget's grain (bounds independent — either alone is valid); `fit` governs the unset bounds: 'data' (the default, absent field included) auto-fits to the periods actually carrying data and follows imports, 'full' spans the whole timeline. `null` clears it (back to fit-to-data)."
      +          },
      +          "position": {
      +            "anyOf": [
      +              {
      +                "properties": {
      +                  "col": {
      +                    "maximum": 11,
      +                    "minimum": 0,
      +                    "type": "integer"
      +                  },
      +                  "row": {
      +                    "maximum": 400,
      +                    "minimum": 0,
      +                    "type": "integer"
      +                  }
      +                },
      +                "required": [
      +                  "col",
      +                  "row"
      +                ],
      +                "type": "object"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "dashboard-child pinned grid origin {col 0–11, row ≥ 0}: the widget sits at these cells (pushed down when it collides with an earlier pinned widget). Absent = flow placement (first-fit dense in sort order — a new widget fills the topmost free hole); null clears the pin. The web canvas pins every widget on the first drag"
      +          },
      +          "role": {
      +            "description": "Role of the item. assumption: a typed input (value / values / timeline_values), the only role a branch overlays. formula: a computed transformation (formula). formula with no expression and children: an aggregator that sums its children (a subtotal value; a nested section is structural grouping with no value). callup: a typed mirror of one source whose value flows into its parent (source): balance flows, a value surfaced in a section or subtotal; a formula references its source directly instead. balance: a rolling stock (opening_balance) that sums its callup-child flows. section: structural container, no value. dashboard / chart / kpi / mini_table: presentational. A formula carrying both an expression and children is rejected (FORMULA_EXPR_AND_CHILDREN). A single bare reference written as a formula is auto-posed as a callup mirror, unless it pins a `timeline_ref` or an `aggregation` different from its source (then it stays a formula).",
      +            "enum": [
      +              "assumption",
      +              "formula",
      +              "callup",
      +              "balance",
      +              "section",
      +              "chart",
      +              "dashboard",
      +              "kpi",
      +              "mini_table"
      +            ],
      +            "type": "string"
      +          },
      +          "row_break": {
      +            "description": "dashboard-child line break (flow widgets only): start this widget on a fresh grid row. Inert once the widget has a position",
      +            "type": "boolean"
      +          },
      +          "row_styles": {
      +            "additionalProperties": {
      +              "enum": [
      +                "normal",
      +                "subtotal",
      +                "total",
      +                "kpi"
      +              ],
      +              "type": "string"
      +            },
      +            "description": "mini_table per-row style override { <row UID / temp ID>: 'normal' | 'subtotal' | 'total' | 'kpi' }; an absent key keeps the row item's own style, a key outside `rows` is dropped, {} clears every override",
      +            "propertyNames": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "object"
      +          },
      +          "rows": {
      +            "description": "mini_table curated row item UIDs / temp IDs / names",
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "series": {
      +            "items": {
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "series_defs": {
      +            "description": "Per-series branch: supersedes `series`. Each entry plots one item under a specific branch (e.g. Revenue@budget vs Revenue@actuals). `uid` accepts a temp id.",
      +            "items": {
      +              "properties": {
      +                "branch_id": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "uid": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "uid"
      +              ],
      +              "type": "object"
      +            },
      +            "type": "array"
      +          },
      +          "source": {
      +            "description": "Callup source UID or temp ID",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "span": {
      +            "description": "dashboard-child grid footprint (chart/kpi/mini_table): cols on the 12-column grid × 140-px row units. Defaults: kpi 3×1, chart/mini_table 6×2",
      +            "properties": {
      +              "cols": {
      +                "maximum": 12,
      +                "minimum": 1,
      +                "type": "integer"
      +              },
      +              "rows": {
      +                "maximum": 4,
      +                "minimum": 1,
      +                "type": "integer"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "sparkline": {
      +            "description": "KPI trend mini-chart under the value.",
      +            "type": "boolean"
      +          },
      +          "target": {
      +            "description": "KPI/mini_table target UID or temp ID",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "target_period": {
      +            "maxLength": 50,
      +            "type": "string"
      +          },
      +          "timeline_ref": {
      +            "enum": [
      +              "constant",
      +              "monthly",
      +              "yearly",
      +              "quarterly"
      +            ],
      +            "type": "string"
      +          },
      +          "timeline_values": {
      +            "additionalProperties": {
      +              "anyOf": [
      +                {
      +                  "anyOf": [
      +                    {
      +                      "type": "number"
      +                    },
      +                    {
      +                      "type": "null"
      +                    }
      +                  ]
      +                },
      +                {
      +                  "items": {
      +                    "anyOf": [
      +                      {
      +                        "type": "number"
      +                      },
      +                      {
      +                        "type": "null"
      +                      }
      +                    ]
      +                  },
      +                  "type": "array"
      +                }
      +              ]
      +            },
      +            "description": "Periodic values, keyed by context. List-mode item: one series per list entry, keyed by the element UID, label, or a `list_create` temp id of the same batch (a temp id is scoped to the batch that declares it; later batches key by label or UID). On `update` the map merges element by element: entries it does not name keep their series (send `[]` to clear one); on `create` / `replace` it is the full set. Non-list item: a sparse per-period patch keyed by period id (`{\"2026-06\": -119.19}`, keys YYYY / YYYY-MM / YYYY-Qn) that rewrites the named cells of the typed `values` series and leaves the rest intact; a full series keyed by a canonical grain (`monthly` / `quarterly` / `yearly` / `constant`) is import-owned and rejected here. A single number is coerced to a 1-element array. List cells left unset read as 0 (no forward-fill).",
      +            "propertyNames": {
      +              "type": "string"
      +            },
      +            "type": "object"
      +          },
      +          "unit": {
      +            "description": "mini_table amount scaling: 'none' (default), 'k' (thousands), 'm' (millions), 'auto' (per-table scale); %, multiples and dates are not divided",
      +            "enum": [
      +              "none",
      +              "k",
      +              "m",
      +              "auto"
      +            ],
      +            "type": "string"
      +          },
      +          "value": {
      +            "anyOf": [
      +              {
      +                "type": "number"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ]
      +          },
      +          "values": {
      +            "items": {
      +              "anyOf": [
      +                {
      +                  "type": "number"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ]
      +            },
      +            "type": "array"
      +          },
      +          "variance": {
      +            "description": "mini_table écart columns (axis=branches)",
      +            "properties": {
      +              "abs": {
      +                "type": "boolean"
      +              },
      +              "color": {
      +                "type": "boolean"
      +              },
      +              "pct": {
      +                "type": "boolean"
      +              }
      +            },
      +            "type": "object"
      +          }
      +        },
      +        "required": [
      +          "role",
      +          "name",
      +          "op"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "from_uid": {
      +            "description": "Existing item UID to replace atomically (section/dashboard unsupported)",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "new_item": {
      +            "description": "Inline payload describing the replacement item",
      +            "properties": {
      +              "aggregation": {
      +                "enum": [
      +                  "sum",
      +                  "average",
      +                  "stock",
      +                  "first"
      +                ],
      +                "type": "string"
      +              },
      +              "axis": {
      +                "description": "mini_table column axis: 'time' (periods, default), 'branches', or 'list' (list entries + Total)",
      +                "enum": [
      +                  "time",
      +                  "branches",
      +                  "list"
      +                ],
      +                "type": "string"
      +              },
      +              "branches": {
      +                "description": "mini_table compared branch ids (axis=branches); first = écart base",
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "bridge_config": {
      +                "properties": {
      +                  "axis": {
      +                    "description": "Bridge dimension: 'time' (default, delta start→end period) or 'branches' (gap between two branches at one period — budget vs actual waterfall).",
      +                    "enum": [
      +                      "time",
      +                      "branches"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  "branches": {
      +                    "description": "Branch ids compared when axis=branches: [from, to].",
      +                    "items": {
      +                      "minLength": 1,
      +                      "type": "string"
      +                    },
      +                    "type": "array"
      +                  },
      +                  "contributions": {
      +                    "items": {
      +                      "minLength": 1,
      +                      "type": "string"
      +                    },
      +                    "type": "array"
      +                  },
      +                  "end_period": {
      +                    "maxLength": 50,
      +                    "type": "string"
      +                  },
      +                  "endpoint": {
      +                    "description": "Single endpoint item (stock/balance) read at start & end periods",
      +                    "minLength": 1,
      +                    "type": "string"
      +                  },
      +                  "endpoint_branch": {
      +                    "description": "Read endpoint + contributions under this branch basis (axis=time only).",
      +                    "minLength": 1,
      +                    "type": "string"
      +                  },
      +                  "residual_label": {
      +                    "maxLength": 200,
      +                    "type": "string"
      +                  },
      +                  "start_period": {
      +                    "maxLength": 50,
      +                    "type": "string"
      +                  }
      +                },
      +                "required": [
      +                  "endpoint"
      +                ],
      +                "type": "object"
      +              },
      +              "by_branch": {
      +                "description": "Chart only: plot one styled series per branch instead of the checked-out view.",
      +                "type": "boolean"
      +              },
      +              "cagr": {
      +                "description": "mini_table (axis=time): show the trailing CAGR column. Default true",
      +                "type": "boolean"
      +              },
      +              "chart_type": {
      +                "enum": [
      +                  "line",
      +                  "bar",
      +                  "area",
      +                  "bridge"
      +                ],
      +                "type": "string"
      +              },
      +              "check": {
      +                "description": "Flags the line as a control judged on its own value at every period: a plain amount passes when within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals, so a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (\"Revenue >= 0\") passes when true. Assumption and formula only. Failing periods surface in `layerz_read` under `health`, non-blocking.",
      +                "properties": {
      +                  "tolerance": {
      +                    "exclusiveMinimum": 0,
      +                    "type": "number"
      +                  }
      +                },
      +                "type": "object"
      +              },
      +              "collapsed": {
      +                "description": "fold the group by default: a section with children, a Σ aggregator or a list-mode line opens collapsed in the web grid and its rows start hidden under the Excel outline (+/−). false unfolds. View state, outside the blueprint and the diffs",
      +                "type": "boolean"
      +              },
      +              "comment": {
      +                "anyOf": [
      +                  {
      +                    "maxLength": 2000,
      +                    "type": "string"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ],
      +                "description": "Free-form annotation on the item (hypothesis source, rationale, review note)."
      +              },
      +              "compare_to": {
      +                "description": "KPI native comparison: a delta vs another branch (`mode:\"branch\"` + `branch_id`) or a shifted period (`prev_period`/`prev_year`). Rendered as the value plus a signed delta %.",
      +                "properties": {
      +                  "branch_id": {
      +                    "minLength": 1,
      +                    "type": "string"
      +                  },
      +                  "display": {
      +                    "enum": [
      +                      "abs",
      +                      "pct",
      +                      "both"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  "mode": {
      +                    "enum": [
      +                      "branch",
      +                      "prev_period",
      +                      "prev_year"
      +                    ],
      +                    "type": "string"
      +                  },
      +                  "thresholds": {
      +                    "properties": {
      +                      "green": {
      +                        "type": "number"
      +                      },
      +                      "red": {
      +                        "type": "number"
      +                      }
      +                    },
      +                    "required": [
      +                      "green",
      +                      "red"
      +                    ],
      +                    "type": "object"
      +                  }
      +                },
      +                "required": [
      +                  "mode"
      +                ],
      +                "type": "object"
      +              },
      +              "default_branch": {
      +                "description": "Dashboard-only: branch checked out when this dashboard opens; overrides the model default.",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "format": {
      +                "description": "Number format name. Pre-installed: default, decimal_2, decimal_neg, integer, multiple, percent, percent_neg, percent_2, date_dmy, date_dmmmyy, date_mmmyy, date_dmmm (+ the magic `date`, and `currency`/`currency_2` — resolved live from the FINANCE.md `currency` code: `$1,234` for USD, `1 234 €` for EUR). Custom names refer to entries in model.formats — add one with the `meta` op `formats` field (same batch OK); the excel_format follows Excel / Google Sheets, bracket colours and conditions included (`[Green]0;[Red](0);-` paints negatives red on the web and in Excel). An unknown name is rejected with code UNKNOWN_FORMAT listing what is available (`percent` is the current name of the legacy `\"%\"`). Full catalog with each excel_format and rendered positive/negative/zero examples (`default` = dash-for-zero accounting style, `integer` = plain 0): MCP resource `format-spec://reference`.",
      +                "maxLength": 50,
      +                "type": "string"
      +              },
      +              "formula": {
      +                "maxLength": 2000,
      +                "type": "string"
      +              },
      +              "inputs": {
      +                "description": "Inputs override of a `formula` item (item UIDs or same-batch temp ids), derived from the expression when omitted. Ignored on every other role: a `balance` takes its flows from its children, an aggregator sums them.",
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "item_style": {
      +                "enum": [
      +                  "normal",
      +                  "subtotal",
      +                  "total",
      +                  "kpi"
      +                ],
      +                "type": "string"
      +              },
      +              "list_mode": {
      +                "description": "Chart only: how a list-backed series renders — 'split' (default) plots one series per list element, 'total' plots the item's aggregate as one series (a list total charted without a mirror formula).",
      +                "enum": [
      +                  "split",
      +                  "total"
      +                ],
      +                "type": "string"
      +              },
      +              "list_total": {
      +                "description": "List-mode only: show the list's total (aggregate row values). Default off; the total is forced ON while any formula/callup/parent/widget reads the aggregate.",
      +                "type": "boolean"
      +              },
      +              "liste": {
      +                "description": "mini_table list whose entries become the columns (axis=list)",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "liste_ref": {
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "monitor": {
      +                "description": "Deprecated (MDK 0.13.0) — use `check`. A canonical assert (\"ABS(value) < t\", \"== 0\") is converted; any other rule is rejected: put it in the line's formula and set `check: {}`.",
      +                "properties": {
      +                  "assert": {
      +                    "maxLength": 200,
      +                    "minLength": 1,
      +                    "type": "string"
      +                  },
      +                  "label": {
      +                    "maxLength": 200,
      +                    "type": "string"
      +                  }
      +                },
      +                "required": [
      +                  "assert"
      +                ],
      +                "type": "object"
      +              },
      +              "name": {
      +                "description": "Display name",
      +                "maxLength": 200,
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "opening_balance": {
      +                "type": "number"
      +              },
      +              "period_mode": {
      +                "description": "kpi / mini_table period mode. 'ytd' shows the year to date: the cumulative from January through the target period (each column for a time-axis mini_table). Flows are summed, an `average` line averaged, a `stock` line read at the period, and a ratio line (formula `a / b`) recomputed on the cumulated operands. Branch columns, écarts and the KPI comparison follow (prev_year = year to date of the same month a year earlier). Default 'period'.",
      +                "enum": [
      +                  "period",
      +                  "ytd"
      +                ],
      +                "type": "string"
      +              },
      +              "period_window": {
      +                "anyOf": [
      +                  {
      +                    "properties": {
      +                      "end": {
      +                        "maxLength": 20,
      +                        "type": "string"
      +                      },
      +                      "fit": {
      +                        "enum": [
      +                          "data",
      +                          "full"
      +                        ],
      +                        "type": "string"
      +                      },
      +                      "start": {
      +                        "maxLength": 20,
      +                        "type": "string"
      +                      }
      +                    },
      +                    "type": "object"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ],
      +                "description": "Display period window of a chart / kpi sparkline / time mini_table. `start`/`end` are period labels at the widget's grain (bounds independent — either alone is valid); `fit` governs the unset bounds: 'data' (the default, absent field included) auto-fits to the periods actually carrying data and follows imports, 'full' spans the whole timeline. `null` clears it (back to fit-to-data)."
      +              },
      +              "position": {
      +                "anyOf": [
      +                  {
      +                    "properties": {
      +                      "col": {
      +                        "maximum": 11,
      +                        "minimum": 0,
      +                        "type": "integer"
      +                      },
      +                      "row": {
      +                        "maximum": 400,
      +                        "minimum": 0,
      +                        "type": "integer"
      +                      }
      +                    },
      +                    "required": [
      +                      "col",
      +                      "row"
      +                    ],
      +                    "type": "object"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ],
      +                "description": "dashboard-child pinned grid origin {col 0–11, row ≥ 0}: the widget sits at these cells (pushed down when it collides with an earlier pinned widget). Absent = flow placement (first-fit dense in sort order — a new widget fills the topmost free hole); null clears the pin. The web canvas pins every widget on the first drag"
      +              },
      +              "role": {
      +                "description": "Role of the item. assumption: a typed input (value / values / timeline_values), the only role a branch overlays. formula: a computed transformation (formula). formula with no expression and children: an aggregator that sums its children (a subtotal value; a nested section is structural grouping with no value). callup: a typed mirror of one source whose value flows into its parent (source): balance flows, a value surfaced in a section or subtotal; a formula references its source directly instead. balance: a rolling stock (opening_balance) that sums its callup-child flows. section: structural container, no value. dashboard / chart / kpi / mini_table: presentational. A formula carrying both an expression and children is rejected (FORMULA_EXPR_AND_CHILDREN). A single bare reference written as a formula is auto-posed as a callup mirror, unless it pins a `timeline_ref` or an `aggregation` different from its source (then it stays a formula).",
      +                "enum": [
      +                  "assumption",
      +                  "formula",
      +                  "callup",
      +                  "balance",
      +                  "section",
      +                  "chart",
      +                  "dashboard",
      +                  "kpi",
      +                  "mini_table"
      +                ],
      +                "type": "string"
      +              },
      +              "row_break": {
      +                "description": "dashboard-child line break (flow widgets only): start this widget on a fresh grid row. Inert once the widget has a position",
      +                "type": "boolean"
      +              },
      +              "row_styles": {
      +                "additionalProperties": {
      +                  "enum": [
      +                    "normal",
      +                    "subtotal",
      +                    "total",
      +                    "kpi"
      +                  ],
      +                  "type": "string"
      +                },
      +                "description": "mini_table per-row style override { <row UID / temp ID>: 'normal' | 'subtotal' | 'total' | 'kpi' }; an absent key keeps the row item's own style, a key outside `rows` is dropped, {} clears every override",
      +                "propertyNames": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "object"
      +              },
      +              "rows": {
      +                "description": "mini_table curated row item UIDs / temp IDs / names",
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "series": {
      +                "items": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "series_defs": {
      +                "description": "Per-series branch: supersedes `series`. Each entry plots one item under a specific branch (e.g. Revenue@budget vs Revenue@actuals). `uid` accepts a temp id.",
      +                "items": {
      +                  "properties": {
      +                    "branch_id": {
      +                      "minLength": 1,
      +                      "type": "string"
      +                    },
      +                    "uid": {
      +                      "minLength": 1,
      +                      "type": "string"
      +                    }
      +                  },
      +                  "required": [
      +                    "uid"
      +                  ],
      +                  "type": "object"
      +                },
      +                "type": "array"
      +              },
      +              "source": {
      +                "description": "Callup source UID or temp ID",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "span": {
      +                "description": "dashboard-child grid footprint (chart/kpi/mini_table): cols on the 12-column grid × 140-px row units. Defaults: kpi 3×1, chart/mini_table 6×2",
      +                "properties": {
      +                  "cols": {
      +                    "maximum": 12,
      +                    "minimum": 1,
      +                    "type": "integer"
      +                  },
      +                  "rows": {
      +                    "maximum": 4,
      +                    "minimum": 1,
      +                    "type": "integer"
      +                  }
      +                },
      +                "type": "object"
      +              },
      +              "sparkline": {
      +                "description": "KPI trend mini-chart under the value.",
      +                "type": "boolean"
      +              },
      +              "target": {
      +                "description": "KPI/mini_table target UID or temp ID",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "target_period": {
      +                "maxLength": 50,
      +                "type": "string"
      +              },
      +              "timeline_ref": {
      +                "enum": [
      +                  "constant",
      +                  "monthly",
      +                  "yearly",
      +                  "quarterly"
      +                ],
      +                "type": "string"
      +              },
      +              "timeline_values": {
      +                "additionalProperties": {
      +                  "anyOf": [
      +                    {
      +                      "anyOf": [
      +                        {
      +                          "type": "number"
      +                        },
      +                        {
      +                          "type": "null"
      +                        }
      +                      ]
      +                    },
      +                    {
      +                      "items": {
      +                        "anyOf": [
      +                          {
      +                            "type": "number"
      +                          },
      +                          {
      +                            "type": "null"
      +                          }
      +                        ]
      +                      },
      +                      "type": "array"
      +                    }
      +                  ]
      +                },
      +                "description": "Periodic values, keyed by context. List-mode item: one series per list entry, keyed by the element UID, label, or a `list_create` temp id of the same batch (a temp id is scoped to the batch that declares it; later batches key by label or UID). On `update` the map merges element by element: entries it does not name keep their series (send `[]` to clear one); on `create` / `replace` it is the full set. Non-list item: a sparse per-period patch keyed by period id (`{\"2026-06\": -119.19}`, keys YYYY / YYYY-MM / YYYY-Qn) that rewrites the named cells of the typed `values` series and leaves the rest intact; a full series keyed by a canonical grain (`monthly` / `quarterly` / `yearly` / `constant`) is import-owned and rejected here. A single number is coerced to a 1-element array. List cells left unset read as 0 (no forward-fill).",
      +                "propertyNames": {
      +                  "type": "string"
      +                },
      +                "type": "object"
      +              },
      +              "unit": {
      +                "description": "mini_table amount scaling: 'none' (default), 'k' (thousands), 'm' (millions), 'auto' (per-table scale); %, multiples and dates are not divided",
      +                "enum": [
      +                  "none",
      +                  "k",
      +                  "m",
      +                  "auto"
      +                ],
      +                "type": "string"
      +              },
      +              "value": {
      +                "anyOf": [
      +                  {
      +                    "type": "number"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ]
      +              },
      +              "values": {
      +                "items": {
      +                  "anyOf": [
      +                    {
      +                      "type": "number"
      +                    },
      +                    {
      +                      "type": "null"
      +                    }
      +                  ]
      +                },
      +                "type": "array"
      +              },
      +              "variance": {
      +                "description": "mini_table écart columns (axis=branches)",
      +                "properties": {
      +                  "abs": {
      +                    "type": "boolean"
      +                  },
      +                  "color": {
      +                    "type": "boolean"
      +                  },
      +                  "pct": {
      +                    "type": "boolean"
      +                  }
      +                },
      +                "type": "object"
      +              }
      +            },
      +            "required": [
      +              "role",
      +              "name"
      +            ],
      +            "type": "object"
      +          },
      +          "op": {
      +            "const": "replace",
      +            "type": "string"
      +          },
      +          "preserve_order": {
      +            "type": "boolean"
      +          },
      +          "preserve_parent": {
      +            "type": "boolean"
      +          },
      +          "preserve_presentation": {
      +            "description": "Default true: every presentation / annotation field `new_item` omits (item_style, format, comment, check, span, position, period_window, compare_to, sparkline, series_defs, …) is carried over from the replaced item when the new role can hold it; `false` rebuilds the item from `new_item` alone.",
      +            "type": "boolean"
      +          },
      +          "preserve_style": {
      +            "type": "boolean"
      +          }
      +        },
      +        "required": [
      +          "op",
      +          "from_uid",
      +          "new_item"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "op": {
      +            "const": "delete",
      +            "type": "string"
      +          },
      +          "uid": {
      +            "description": "UID of item to delete",
      +            "minLength": 1,
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "op",
      +          "uid"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "after": {
      +            "description": "UID of item to place after (for ordering)",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "op": {
      +            "const": "move",
      +            "type": "string"
      +          },
      +          "parent": {
      +            "description": "New parent UID",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "uid": {
      +            "description": "UID of item to move",
      +            "minLength": 1,
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "op",
      +          "uid"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "id": {
      +            "description": "Temp ID for intra-batch references — other create ops in the same batch can pass this value as their `liste_ref` so a list and its consumers can ship in one patch (e.g. set `id: \"_emp\"` on `list_create`, then `liste_ref: \"_emp\"` on an assumption created in the same batch).",
      +            "maxLength": 32,
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "items": {
      +            "items": {
      +              "properties": {
      +                "id": {
      +                  "maxLength": 32,
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "label": {
      +                  "maxLength": 200,
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "mapped_to": {
      +                  "additionalProperties": {
      +                    "items": {
      +                      "type": "string"
      +                    },
      +                    "type": "array"
      +                  },
      +                  "propertyNames": {
      +                    "type": "string"
      +                  },
      +                  "type": "object"
      +                },
      +                "uid": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "label"
      +              ],
      +              "type": "object"
      +            },
      +            "maxItems": 500,
      +            "type": "array"
      +          },
      +          "name": {
      +            "maxLength": 200,
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "op": {
      +            "const": "list_create",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "op",
      +          "name"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "items": {
      +            "items": {
      +              "properties": {
      +                "id": {
      +                  "maxLength": 32,
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "label": {
      +                  "maxLength": 200,
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "mapped_to": {
      +                  "additionalProperties": {
      +                    "items": {
      +                      "type": "string"
      +                    },
      +                    "type": "array"
      +                  },
      +                  "propertyNames": {
      +                    "type": "string"
      +                  },
      +                  "type": "object"
      +                },
      +                "uid": {
      +                  "minLength": 1,
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "label"
      +              ],
      +              "type": "object"
      +            },
      +            "maxItems": 500,
      +            "type": "array"
      +          },
      +          "name": {
      +            "maxLength": 200,
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "op": {
      +            "const": "list_update",
      +            "type": "string"
      +          },
      +          "uid": {
      +            "minLength": 1,
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "op",
      +          "uid"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "op": {
      +            "const": "list_delete",
      +            "type": "string"
      +          },
      +          "uid": {
      +            "description": "UID of list to delete",
      +            "minLength": 1,
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "op",
      +          "uid"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "properties": {
      +          "default_branch": {
      +            "anyOf": [
      +              {
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ]
      +          },
      +          "finance_md": {
      +            "anyOf": [
      +              {
      +                "maxLength": 5000,
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ]
      +          },
      +          "formats": {
      +            "additionalProperties": {
      +              "properties": {
      +                "display_name": {
      +                  "maxLength": 80,
      +                  "type": "string"
      +                },
      +                "excel_format": {
      +                  "maxLength": 120,
      +                  "minLength": 1,
      +                  "type": "string"
      +                },
      +                "name": {
      +                  "maxLength": 50,
      +                  "minLength": 1,
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "name",
      +                "excel_format"
      +              ],
      +              "type": "object"
      +            },
      +            "propertyNames": {
      +              "maxLength": 50,
      +              "minLength": 1,
      +              "type": "string"
      +            },
      +            "type": "object"
      +          },
      +          "glyph": {
      +            "anyOf": [
      +              {
      +                "maxLength": 60,
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Model emblem icon: a kebab-case Lucide icon name (https://lucide.dev/icons), e.g. \"trending-up\", \"coffee\", \"landmark\", \"rocket\", \"house\", \"users\". Shown in-app and on the social/OG card. Emojis and free text are rejected with suggestions. Aliases normalized: cash/money→banknote, bank→landmark, cart→shopping-cart, chart/graph→chart-line. `null` clears it (falls back to a monogram of the model name)."
      +          },
      +          "name": {
      +            "maxLength": 100,
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "number_locale": {
      +            "anyOf": [
      +              {
      +                "enum": [
      +                  "en",
      +                  "fr",
      +                  "de"
      +                ],
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ]
      +          },
      +          "op": {
      +            "const": "meta",
      +            "type": "string"
      +          },
      +          "subtitle": {
      +            "anyOf": [
      +              {
      +                "maxLength": 160,
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ]
      +          },
      +          "timelines": {
      +            "properties": {
      +              "monthly": {
      +                "anyOf": [
      +                  {
      +                    "properties": {
      +                      "end": {
      +                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +                        "type": "string"
      +                      },
      +                      "start": {
      +                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +                        "type": "string"
      +                      }
      +                    },
      +                    "required": [
      +                      "start",
      +                      "end"
      +                    ],
      +                    "type": "object"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ]
      +              },
      +              "quarterly": {
      +                "anyOf": [
      +                  {
      +                    "properties": {
      +                      "end": {
      +                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +                        "type": "string"
      +                      },
      +                      "start": {
      +                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +                        "type": "string"
      +                      }
      +                    },
      +                    "required": [
      +                      "start",
      +                      "end"
      +                    ],
      +                    "type": "object"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ]
      +              },
      +              "yearly": {
      +                "anyOf": [
      +                  {
      +                    "properties": {
      +                      "end": {
      +                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +                        "type": "string"
      +                      },
      +                      "start": {
      +                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +                        "type": "string"
      +                      }
      +                    },
      +                    "required": [
      +                      "start",
      +                      "end"
      +                    ],
      +                    "type": "object"
      +                  },
      +                  {
      +                    "type": "null"
      +                  }
      +                ]
      +              }
      +            },
      +            "type": "object"
      +          }
      +        },
      +        "required": [
      +          "op"
      +        ],
      +        "type": "object"
      +      }
      +    ]
      +  },
      +  "maxItems": 100,
      +  "minItems": 1,
      +  "type": "array"
      +}
  3. Changed5 schema fields changed
    • addedInput schema / properties / dataset_id / description
      Added value: +"Branch to update. Absent: the branch named `patch.display_name` is updated when it exists, created otherwise."
    • changedInput schema / properties / model_id / description
      Previous value: -"Target model UUID. Required for user-scoped API keys; ignored (or validated against scope) for model-scoped keys."New value: +"Target model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys."
    • addedInput schema / properties / patch / properties / actuals_through / description
      Added value: +"Real/forecast cutover (YYYY-MM). A value pins it against source syncs; `null` resets it to auto."
    • changedInput schema / properties / summary / description
      Previous value: -"Required: short human-readable note (3–100 chars) summarising what this change does. Shown as the label in the model version history. Be specific (e.g. \"Renamed Revenue to Net Revenue\", \"Imported 2024 OPEX from Excel\")."New value: +"Short note (3–100 chars) describing the change, stored as the label of the resulting version. Examples: \"Renamed Revenue to Net Revenue\", \"Imported 2024 OPEX from Excel\"."
    • changedInput schema / required
      Previous value: -[
      -  "summary",
      -  "dataset_id",
      -  "patch"
      -]New value: +[
      +  "summary",
      +  "patch"
      +]
  4. First observed

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses that a version is persisted labelled with `summary`, that `actuals_through` pins the real/forecast cutover (`actuals_through_locked: true`, source syncs stop rewriting it) and `null` resets to auto, and that the tool is not advertised to read-only keys. It does not clarify what the `destructiveHint: true` actually destroys, which is the main residual ambiguity for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then proceeds through selector behavior, ops, edge rules, and return shape in a logical order with no filler. It is dense and somewhat packed with backticked clauses, but nearly every sentence carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nested-object mutation tool with no output schema, the description covers input modes, op application, edge cases (default-branch priority), return payload (`{ branch, created }`), and versioning side effects. An agent could invoke this correctly without further exploration.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Adds real meaning beyond an already 80%-covered schema: `dataset_id` is framed as the branch selector with defined absent-behavior, `actuals_through` semantics (pinning vs auto reset) are spelled out, and `priority`'s default-branch rejection is stated. The `patch` sub-fields like `source_hint` and `file_name` are echoed but not semantically explained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ("Creates or updates a branch") and immediately differentiates the two modes by the presence of `dataset_id`. It also distinguishes itself from `layerz_patch` by explaining that `ops` behave "as `layerz_patch { branch_id }` would".

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete conditional guidance: with `dataset_id` it patches that branch's metadata, without it the branch named `patch.display_name` is updated-or-created with no data source and no input rows. It also flags that `priority` is rejected on the default branch and that ops can be combined in one call rather than two. It stops short of an explicit "prefer layerz_patch when..." exclusion, which is the only gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources