Skip to main content
Glama

Server Details

A structured financial modeling layer for AI agents. Build, version, and audit financial models without drift, then export to Excel, from Claude or any MCP client. Learn more: https://layerz.cc/for-agents

Ownership verified
Status
Healthy
Uptime
45.6% over 53 days
OAuth
Works in Glama
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL

TDQS

A3.8/5.0

Scored across 30 tools

Disambiguation3/5

Several tool boundaries overlap: layerz_get_model vs layerz_read both return model state, while branch value writes are spread across layerz_import_branch, layerz_patch { branch_id }, and layerz_manage_integration { op: "sync" }; layerz_update_branch and layerz_import_branch can both create branches. The descriptions work hard to distinguish these paths, but an agent can still easily pick the wrong write tool for a branch update.

Naming Consistency4/5

All tools use the layerz_ prefix with snake_case, and most follow a predictable verb_noun pattern (layerz_list_models, layerz_create_model, layerz_manage_mapping, layerz_delete_branch). A few deviate by using noun-only names such as layerz_diff, layerz_history, layerz_dependencies, and layerz_external_ref, but the overall style remains uniform and readable.

Tool Count2/5

30 tools is a heavy surface for a single MCP server and exceeds the 25-tool threshold where the set starts to feel unwieldy. While the domain is broad, several tool families (model reading, branch writing, version comparison) could likely be consolidated, reducing the chance of misselection.

Completeness3/5

Core model lifecycle is broadly covered, but there is no layerz_delete_model, creating a clear dead end for cleanup and common CRUD expectations. Template lifecycle is also incomplete (promote exists but no unpromote or delete), and branch value writes are fragmented across multiple tools rather than centralized.

Available Tools

30 tools
layerz_build_from_blueprintBuild from blueprintA
Destructive
Inspect

Builds or extends a model from a strict Blueprint (whole sections with their hierarchy, items referenced by name), or applies a stored template as a module through template_id (mutually exclusive with blueprint, loaded server-side). mode: 'merge' (default) adds to the model, reusing items by name and keeping the presentation fields a re-declared item omits; mode: 'replace' rebuilds the whole model (structure, timelines, values, branches), keeping style colours, custom formats, locale, glyph, subtitle and FINANCE.md. dry_run: true validates and returns errors with their path without writing. Persists one version labelled with summary. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNo'merge' (default): adds to the existing model, reusing items by name. 'replace': rebuilds the whole model from the blueprint.
dry_runNoValidates the blueprint and reports errors without writing.
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.
blueprintNoStrict Blueprint object: { project?, timelines?: { monthly? | quarterly? | yearly?: { start, end } }, lists?: [{ display_name, items: [{ label, mapped_to?: Record<listName, labels[]> }] }], sections: [{ name, items: [{ role, name, timeline_ref?, value?, values?, formula?, item_style?, opening_balance?, liste_ref?, timeline_values?: Record<elementLabel, (number|null)[]>, children?, … }] }], dashboards?: [{ name, items: [{ role: chart | kpi | mini_table, … }] }] }. At least one section is required. Items reference each other by name (formula inputs, callup source, chart series); a callup omits `name` and inherits its source's. A list-mode item binds a declared list through `liste_ref` and carries `timeline_values` keyed by element label; a `balance` with `liste_ref` requires every list-typed child to share it. Accepted as a JSON object or a JSON-encoded string.
template_idNoStored template to apply as a module (mutually exclusive with `blueprint`).

TDQS

A4.6/5.0
Behavior5/5

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

Adds substantial context beyond the annotations: what `replace` rebuilds (structure, timelines, values, branches) versus what it preserves (style colours, custom formats, locale, glyph, subtitle, FINANCE.md), what `merge` retains for re-declared items, that one version is persisted, and that the tool is not exposed to read-only keys. This is consistent with destructiveHint=true and enriches it.

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, and each sentence carries distinct semantics (modes, dry-run, versioning, key scoping). Dense multi-clause sentences make it slightly heavy, but nothing is wasted given the tool's complexity.

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?

With no output schema, the description covers write behavior, validation feedback, version persistence, and permission scope. An agent has everything needed to call this destructive, schema-complex tool correctly.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning the schema lacks: the mutual-exclusivity constraint between `blueprint` and `template_id`, that templates are loaded server-side, and that `dry_run` returns errors with their path. The blueprint shape explanation largely duplicates the schema description.

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?

States a specific verb and resource ('builds or extends a model') plus the two input paths (Blueprint vs stored template). It clearly distinguishes itself from siblings like layerz_create_model and layerz_patch by describing full model construction/replacement rather than single edits.

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?

Explains the selection conditions for `mode: 'merge'` vs `'replace'`, the mutual exclusivity of `blueprint` and `template_id`, and the validation path via `dry_run`. It does not explicitly route the agent away from sibling tools such as create_model or patch, so it stops short of full when-not guidance.

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

layerz_create_modelCreate modelAInspect

Creates a model and returns its detail with its UUID. template_id forks a template into the new model (sources, staged transactions and mapping rules copied under fresh ids; connector credentials excluded), timelines sets its bounds, glyph its emblem (a kebab-case Lucide icon name, e.g. SaaS trending-up, banking landmark, real estate house, coffee shop coffee, energy wind, HR users, valuation scale, treasury wallet). Rejected past the plan model cap. Not advertised to model-scoped or read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
glyphNoEmblem icon: a kebab-case Lucide icon name (https://lucide.dev/icons), e.g. "trending-up", "coffee", "landmark". Shown in-app and on the social/OG card. Emojis/free text are rejected with suggestions. Aliases: cash/money→banknote, bank→landmark, cart→shopping-cart, chart/graph→chart-line.
subtitleNo
timelinesNo
template_idNo

TDQS

A4/5.0
Behavior5/5

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

Annotations only declare readOnlyHint=false, destructiveHint=false, openWorldHint=false. The description adds substantial behavior beyond that: the fork semantics of template_id (sources, staged transactions and mapping rules copied under fresh ids, connector credentials excluded), the plan-cap rejection, and the key-scope restriction. These are exactly the non-obvious traits an agent needs before invoking a mutation.

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-loads the core purpose and return value, then handles parameters in a single dense parenthetical. The glyph example list (SaaS trending-up, banking landmark, real estate house, coffee shop coffee, energy wind, HR users, valuation scale, treasury wallet) is longer than needed and partly duplicates the schema's own glyph examples, which costs some efficiency.

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

Completeness4/5

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

With no output schema and thin annotations, the description carries most of the burden and does so well for a 5-parameter nested-object tool: it covers the return value, fork side effects, hard limits, and credential exclusions. Remaining gaps are secondary (subtitle semantics, timeline defaults/structure), not enough to block a correct call.

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?

Schema description coverage is only 20%, so the description must compensate, and it largely does: template_id's fork behavior and timelines' bounds-setting role are explained in prose even though neither parameter is documented in the schema. subtitle is never explained, and the internal structure of timelines (yearly/monthly/quarterly) is not described, leaving a modest gap.

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

Purpose4/5

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

States a specific verb and resource ('Creates a model') and adds the return shape ('returns its detail with its UUID'), which is useful since no output schema exists. It does not explicitly distinguish itself from the other creation-flavored sibling layerz_build_from_blueprint, so the boundary is left to inference.

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

Usage Guidelines3/5

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

The description gives real preconditions ('Rejected past the plan model cap', 'Not advertised to model-scoped or read-only keys') which tell the agent when the call will fail, but it never says when to prefer this over layerz_build_from_blueprint or other sibling creation paths. Usage is implied rather than routed.

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

layerz_create_upload_urlCreate file upload URLAInspect

Issues a 24h signed Storage URL for an Excel/CSV file and returns file_id, signed_url, expires_at. signed_url accepts an HTTP PUT of the file body with the declared content type (a shell curl -X PUT --data-binary @file; the binary stays out of the conversation); file_id is the identifier the file-consuming tools take. Limits: 25 MB, MIME whitelist (xlsx, xls, csv, json, txt). Mints no model data, so it stays available to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
sizeYesFile size in bytes (max 25 MB).
filenameYesOriginal filename, e.g. "actuals_q1.csv".
content_typeYesMIME type, e.g. "text/csv" or the xlsx content type.

TDQS

A4.5/5.0
Behavior5/5

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

Adds substantial context beyond the annotations: 24h expiry, the PUT-with-declared-content-type mechanic, a concrete curl example, the note that the binary stays out of the conversation, the 25 MB cap, the MIME whitelist, and the 'mints no model data, so it stays available to read-only keys' authorization note. This is exactly the behavioral disclosure the annotations alone would not convey.

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

Conciseness5/5

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

Dense yet well-ordered: the core action and return values come first, followed by the invocation mechanic, then limits and the availability note. No sentence is filler.

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?

There is no output schema, so the description carries the return contract and does so completely (file_id, signed_url, expires_at). Limits, MIME whitelist, and the read-only-key accessibility round out what an agent needs to call it correctly.

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

Parameters3/5

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

Schema description coverage is 100%, so the three parameters are already documented in the schema. The description restates the 25 MB limit and MIME whitelist but adds no new per-parameter syntax or format guidance, so the baseline of 3 applies.

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?

States a specific verb and resource: 'Issues a 24h signed Storage URL for an Excel/CSV file.' It clearly identifies the tool as an upload-URL minter, which is readily distinguishable from file-related siblings like layerz_parse_file and layerz_export.

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?

Implies the intended workflow by noting 'file_id is the identifier the file-consuming tools take' and that the signed_url accepts a PUT, which tells an agent how to chain it with downstream tools. It stops short of explicitly naming those alternatives or stating when-not to use it, so it does not reach a 5.

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

layerz_delete_branchDelete branchA
Destructive
Inspect

Deletes a branch, every input row tagged with its dataset_id, and the data sources that fed only that branch (their staged transactions with them); a source shared with another branch is detached instead. The default branch is rejected. Returns deleted_dataset_id, inputs_removed, sources_removed. Persists one version labelled with summary. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
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_idYes

TDQS

A4.7/5.0
Behavior5/5

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

While annotations already flag destructiveHint=true, the description adds substantial context beyond them: exact cascade semantics, the detachment of shared sources, default-branch rejection, the version persisted with the summary label, the returned counters, and read-only key exclusion.

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

Conciseness5/5

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

Dense and front-loaded: each clause carries a distinct fact (scope, shared-source rule, precondition, return fields, version, auth). No filler sentences; nothing could be removed without losing 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?

With no output schema, the description enumerates the return fields, and it covers preconditions and side effects for a destructive multi-entity mutation. Nothing an agent needs to invoke this safely appears to be missing.

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?

Schema coverage is 67% and the description compensates: it clarifies that dataset_id identifies the branch being deleted and that summary labels the persisted version. The undocumented model_id is only weakly covered ('Not advertised to read-only keys' implies key scoping but doesn't explain the model_id requirement).

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?

The description opens with a specific verb+resource ('Deletes a branch') and immediately details the cascade scope (input rows tagged with the dataset_id, exclusive data sources, detachment for shared sources). This distinguishes it sharply from layerz_update_branch and the other branch/model siblings.

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?

It gives clear conditions: the default branch is rejected and read-only keys don't see it, and it explains the shared-source detachment rule. It stops short of explicitly naming an alternative (e.g., update_branch) for the case where a delete isn't wanted, so it's strong context but not full when/when-not routing.

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

layerz_dependenciesTrace dependenciesA
Read-only
Inspect

Returns an item's dependency graph, like Excel trace precedents / dependents: precedents (items its formula references) and dependents (items referencing it). depth (1–5) walks transitively, direction restricts to one side.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesItem UID to trace (role-prefixed forms accepted)
depthNoTransitive depth to walk (1 = direct only). Default: 1.
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
directionNo'precedents' = what feeds the item, 'dependents' = what references it, 'both' (default).

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false and closed-world scoping, so the safety profile is covered. The description adds useful conceptual detail on what a traversal yields, but says nothing about response size, limits, pagination, or cost of deeper walks.

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

Conciseness5/5

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

Two tight sentences, front-loaded with the return shape, then the parameters. No filler or redundancy.

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

Completeness4/5

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

With no output schema, the description usefully characterizes the returned fields (precedents/dependents), which is the key informational need. It omits mention of traversal limits, failure modes (cycles, missing uid), or scoping constraints, leaving a small gap for a graph tool with transitive walks.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3. The description restates depth (1–5, transitive) and the direction enum values, largely duplicating the schema rather than adding format or edge-case detail the schema lacks.

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?

States a specific verb and resource ('Returns an item's dependency graph') and grounds it with a concrete Excel trace-precedents analogy. No sibling tool (read, diff, history, match_items) performs dependency tracing, so an agent can identify this unambiguously.

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

Usage Guidelines3/5

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

Usage is implied by the Excel analogy and the direction/depth knobs, but there is no explicit when-to-use statement or routing away from neighbors like layerz_read or layerz_diff. No prerequisites (e.g. model_id scoping needs) are mentioned even though the schema handles them.

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

layerz_diffDiff two versionsA
Read-only
Inspect

Returns the semantic diff between two revisions of a model: { from, to, diff: { items: [{ uid, displayName, status, fields? }], branches: [{ id, display_name, status?, items }], metadata: [...], summary: { added, removed, modified, branches } } }. items compares the base plan; branches lists, per branch, the overlay cells it records over the base (value / values / timeline_values, null where the base shows through) — a write under branch_id or an import on a branch appears there, not as a base change. from and to each take exactly one of revision_id, version_number or id; without to, the diff runs against the live model.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoNewer endpoint; omitted = the current live model.
fromYesOlder endpoint: exactly one of revision_id / version_number / id.
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.

TDQS

A3.9/5.0
Behavior5/5

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

With readOnlyHint/destructiveHint already covering the safety profile, the description goes well beyond them by disclosing the full return shape and, critically, the semantics of branch overlays ('a write under branch_id or an import on a branch appears there, not as a base change'). That distinction would otherwise cause an agent to misread the diff.

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?

It is front-loaded with the purpose and then the return contract, with no filler sentences. The inline shape dump is dense and verbose, but since no output schema exists it earns its place by carrying the return contract.

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

Completeness4/5

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

For a 3-parameter, nested-object read tool with no output schema, the description adequately covers inputs and return structure, especially the branch-vs-base distinction. It omits any mention of the `model_id` scoping requirement for user-scoped keys, a minor gap given the schema documents it.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents the `from`/`to`/`model_id` shapes and their UUID/revision semantics. The description largely restates these ('exactly one of revision_id / version_number / id', 'omitted = live model') rather than adding new syntax or format detail, so the baseline of 3 applies.

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

Purpose4/5

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

The opening sentence names a specific verb and resource ('Returns the semantic diff between two revisions of a model'), so the operation is unambiguous. It never names or contrasts itself with a sibling such as layerz_history, so it stops short of full differentiation.

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

Usage Guidelines3/5

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

It clarifies the default behavior ('without `to`, the diff runs against the live model'), which is useful selection context. However, it never says when to pick this tool over layerz_history or other read tools, and offers no exclusions or prerequisites.

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

layerz_exportExport to ExcelA
Read-only
Inspect

Generates the model as an Excel workbook (the same export as the web app: Intro + per-section sheets, native charts and dashboards, live formulas) and returns { download_url, filename, size, file_id, expires_at, structure_hash, values_hash }. The file is stored out-of-band in private Storage; the signed download_url and the file expire after 24h (a new call issues a fresh one). When the model has branches, the statements and single-value widgets follow branch_id (default: the base branch) while dashboards keep every branch they break down by. A read operation, available to read-only keys, off quota.

ParametersJSON Schema
NameRequiredDescriptionDefault
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
branch_idNoBranch the statements and single-value widgets follow (default: the base branch). Dashboards keep every branch.

TDQS

A4.4/5.0
Behavior5/5

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

Goes well beyond the readOnly/destructive annotations: the file is stored out-of-band in private Storage, the signed download_url and file expire after 24h and require a fresh call, dashboards retain all branches while statements follow branch_id, and it works with read-only keys without consuming quota. These are exactly the side effects and lifecycle facts an agent needs.

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 action and artifact, then the return shape, then lifecycle and branch rules. The parenthetical enumerations are informative rather than filler, though the dense multi-clause sentences make it slightly heavier than necessary.

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?

With no output schema, the description compensates by enumerating the return fields (download_url, filename, size, file_id, expires_at, structure_hash, values_hash), and it covers expiry, storage handling, branch semantics, and authorization. An agent has everything needed to call and consume the result.

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

Parameters3/5

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

Schema coverage is 100% and the schema already documents both model_id (key scoping/validation) and branch_id (default base branch, dashboards keep all branches). The description restates the branch behavior in essentially the same terms rather than adding new semantics, so the baseline 3 applies.

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?

States a specific verb and resource ('Generates the model as an Excel workbook') and immediately qualifies the artifact ('Intro + per-section sheets, native charts and dashboards, live formulas'). No sibling tool offers export, so the agent can distinguish it cleanly from read/patch/history tools.

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?

Clearly signals the context of use (exporting the model to Excel) and adds operational constraints ('a read operation, available to read-only keys, off quota') plus branch-selection guidance. It stops short of naming when-not-to-use conditions or an alternative tool, so it is clear but not fully exclusionary.

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

layerz_external_refLink, refresh or unlink external referenceA
Destructive
Inspect

Manages the links from this model to items of other Layerz models (an external ref, like an Excel linked workbook), by op. link: creates (or retargets, with uid) a non-list assumption whose values hold a snapshot of the source item's computed series projected to this model's grain (null outside the source's coverage); requires read access to the source model; the line is referenceable in formulas like any assumption; up to 200 links in links (one form per call) load each source once, are validated whole (one failure writes nothing) and return results. refresh: re-reads every linked source (or uids) and rewrites the snapshots, the only way the values move; a per-link failure (source or item gone) leaves the stored values intact; when values change, the pre-refresh state is snapshotted first (Auto-backup before refresh). unlink: detaches the line uid, keeping its values as an ordinary assumption. A self-link is rejected; a cross-model cycle resolves one hop per refresh. Link status and staleness: layerz_list_integrations { include_external_refs: true }. Persists one version labelled with summary. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
opYeslink | refresh | unlink.
uidNo`link`: existing non-list assumption to retarget. `unlink`: the linked line to detach.
nameNo`link`: display name (default: the source item's name).
uidsNo`refresh`: restricts the refresh to these linked items (default: all).
linksNo`link`: up to 200 links written as one batch, in place of the flat fields.
parentNo`link` (create): parent container uid (section / formula / balance / dashboard).
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.
source_uidNo`link`: uid of the source item in that model.
timeline_refNo`link`: grain of the linked line (default: the source's grain when active here, else the finest active grain).
source_model_idNo`link`: the model read from.

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already flag destructiveHint=true and openWorldHint=false, but the description adds substantial non-obvious behavior: batch validation is all-or-nothing (one failure writes nothing), per-link refresh failures leave stored values intact, values are auto-backed-up before a refresh that changes them, self-links are rejected, cycles resolve one hop per refresh, and it persists a version labelled with `summary`. This is exactly the kind of context annotations cannot carry.

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?

One dense paragraph, front-loaded with the tool's purpose and the op enumeration before details. It is long, and the per-op clauses are packed tightly with backticked field names, but nearly every clause conveys distinct operational behavior rather than filler.

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 multi-op, destructive, 11-parameter tool with no output schema, the description covers effect, failure modes, limits, versioning, and access scoping (not advertised to read-only keys), and even notes that link returns `results`. Nothing an agent needs to invoke it correctly appears missing.

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?

Schema coverage is 100%, so the baseline is 3, but the description goes further than the schema by explaining that uid retargets an existing assumption on link, that refresh uids restrict scope, that links is a batch form of the flat fields capped at 200, and that null values mean outside the source's coverage. Only the required-summary and model_id scoping details are left to the schema.

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?

The description names the specific resource (links from this model to items of other Layerz models) and the three operations (`link`, `refresh`, `unlink`), each with a concrete effect. An agent can distinguish this from siblings like layerz_manage_integration or layerz_dependencies without opening the schema.

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?

Each op carries its own usage context (link creates/retargets, refresh is the only way values move, unlink detaches but keeps values), and it routes the agent to layerz_list_integrations { include_external_refs: true } for status/staleness. It stops short of naming when NOT to use this tool versus other link/integration-management siblings.

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

layerz_get_conventionsGet conventionsA
Read-only
Inspect

Returns the conventions the tools' values are expressed in: custom_instructions (the user's account-wide instructions for AI agents, ≤ 3000 chars, empty string when unset; also delivered in the handshake instructions) and, when a model is targeted, finance_md (the model's FINANCE.md: raw Markdown, source, spec_version, parsed front_matter with currency / units / sign convention / glossary, validation_errors; null when the model has none). include_guide: true adds guide, the modeling guide (session workflow, structure, stock-flow, lists, branches, sources, templates, checks, versions; also the resource modeling-guide://reference).

ParametersJSON Schema
NameRequiredDescriptionDefault
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
include_guideNoAlso return the modeling guide (Markdown).

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already establish readOnly/destructive/openWorld=false, so the bar is lower; the description still adds substantial behavior: the 3000-char cap and empty-string-when-unset for `custom_instructions`, and `null` when a model lacks a FINANCE.md, plus the presence of `validation_errors` and parsed `front_matter`. It does not cover auth/latency, but for a read tool this is well beyond what annotations provide.

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

Conciseness3/5

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

Front-loaded with the core purpose, but the body is two very dense sentences packed with nested parentheticals and an eleven-item inline list, which reads closer to a data dump than a scannable spec. Every clause carries information, yet the structure makes it harder to parse than it needs to be.

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?

There is no output schema, so the description carries the return-shape burden entirely, and it does so thoroughly: field names, types, null/empty semantics, and the optional guide. Nothing an agent needs in order to call this correctly or interpret the result is missing.

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?

Schema coverage is 100%, so baseline is 3, but the description adds real meaning: it clarifies that `model_id` scopes the `finance_md` portion and that `include_guide: true` injects the full `guide` with its section list. That goes beyond the schema's terse one-liners.

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?

States a specific verb+resource (returns the conventions values are expressed in) and immediately enumerates the two concrete payloads, `custom_instructions` and `finance_md`. The subject matter is unmistakably distinct from siblings like get_model or list_models, so an agent can route to it without inference.

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?

Explains the conditional trigger for `finance_md` ('when a model is targeted') and notes the alternatives for the same content ('also delivered in the handshake instructions', 'also the resource modeling-guide://reference'). It gives clear context and a redundancy pointer, though it never says explicitly when to prefer this tool over fetching the guide resource.

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

layerz_get_modelGet model detailA
Read-only
Inspect

Returns the full detail of a model: items, lists, timelines, custom formats, number_locale, glyph, revision_id (sha256 fingerprint) and version_number, plus branches[] (id, display_name, priority, actuals_through, actuals_through_locked) and sharing with the roster (members[]: owner, collaborators and pending invites with their roles and ids, is_owner, link_visibility: invite = sign-in required, public = anyone with the link reads it). Larger payload than layerz_read, which returns a filtered snapshot.

ParametersJSON Schema
NameRequiredDescriptionDefault
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered, and the description adds real context: it specifies the shallow-world scope, the revision_id fingerprint, and decodes link_visibility semantics ('invite' = sign-in required, 'public' = anyone with the link reads it). It doesn't mention pagination or rate limiting, so not a 5.

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?

The definition is a single dense, front-loaded sentence that enumerates return contents efficiently, with the layerz_read contrast placed at the end. The nested inline lists make it harder to scan than a fully terse version, but every clause carries 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?

There is no output schema, so the description carries the return-value burden, and it does this thoroughly by listing the top-level fields and the nested branches[] and sharing.roster structures. An agent knows what to expect from the call without any output schema.

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

Parameters3/5

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

Schema description coverage is 100% and the single model_id parameter is fully documented in the schema (UUID format, key-scoping behavior). The description adds nothing about the parameter, so the baseline of 3 for a schema-complete single param is appropriate.

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?

The description uses a specific verb ('Returns the full detail') plus resource ('of a model') and enumerates the concrete fields returned (items, lists, timelines, formats, revision_id, branches, sharing). It explicitly distinguishes itself from the sibling layerz_read by contrasting payload scope ('Larger payload than layerz_read, which returns a filtered snapshot').

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?

It names the alternative tool (layerz_read) and gives the distinguishing condition (full detail vs filtered snapshot), so an agent can choose between the two. It does not state explicit when-not conditions or prerequisites for either, so it falls short of a full 5.

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

layerz_historyList version historyA
Read-only
Inspect

Returns the version history of a model, newest first: { current_revision_id, current_version_number, history_days, hidden_count, oldest_hidden_at, pinned_count, max_pinned_versions, versions: [{ revision_id, version_number, created_at, trigger_type, actor_user_id, label, conversation_id, pinned }] }. Each version is a full snapshot persisted at one mutation boundary; revision_id (sha256 of the snapshot) is stable while the model is unchanged. Versions older than the plan window are counted in hidden_count but not listed; pinned versions stay listed whatever their age. limit and since scope the list. With uid, returns instead that item's change events across the history: { uid, events: [{ revision_id, version_number, created_at, actor_user_id, trigger_type, status: added | removed | modified, fields?: [{ field, oldValue, newValue }], branches?: [{ id, display_name, status, fields? }] }] } — fields describes the base plan, branches the overlay cells a branch records over it (a write under branch_id or an import on a branch lands there, not in fields).

ParametersJSON Schema
NameRequiredDescriptionDefault
uidNoItem UID: returns that item's change events instead of the version list.
limitNoMax versions returned (default 100; with `uid`, max versions scanned, default 50).
sinceNoISO timestamp lower bound on the version list (ignored with `uid`).
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.

TDQS

A4/5.0
Behavior5/5

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

With annotations covering read-only safety, the description adds substantial behavioral context: newest-first ordering, hidden versions counted but not listed, pinned versions always listed, snapshot semantics at mutation boundaries, and the distinct return shapes for list vs. event modes. It also explains how `fields` and `branches` relate to the base plan and overlay cells.

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?

The description is front-loaded with the purpose and the primary return shape, then explains exceptions and the alternate mode. It is dense but every sentence carries necessary information, especially given the absence of an output schema. The use of inline object notation is efficient but may be slightly hard to scan.

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 tool with no output schema, the description compensates thoroughly by documenting the full return shape in both modes, the behavior of hidden and pinned versions, and the effect of each parameter. The only minor gap is the model_id requirement for user-scoped keys, which is covered in the schema. Overall, an agent has everything needed to invoke and interpret the result.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3. The description reiterates the effect of `limit` and `since` in the list mode and clarifies that `since` is ignored with `uid`, but this largely duplicates what the schema already states. No additional syntax or format details are provided beyond the schema.

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

Purpose4/5

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

The description clearly states the verb and resource: 'Returns the version history of a model, newest first.' It also explains the dual-mode behavior with `uid`, which is specific and useful. However, it never distinguishes this tool from siblings like `layerz_manage_version` or `layerz_diff`, so it falls short of the top score.

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

Usage Guidelines3/5

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

No explicit when-to-use or when-not-to-use guidance is given. The description describes behavior modes (list vs. change events) but leaves the choice to the agent based on the `uid` parameter. There is no mention of alternatives or prerequisites.

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

layerz_import_branchImport data into branchA
Destructive
Inspect

Writes values onto a branch of the model, creating the branch when branch.id names none (branch.display_name required then; branch.actuals_through sets its cutover). Two sources, mutually exclusive: entries[] (one value per item and period; items resolved by item_uid or item_label, created as assumptions when absent; entry_uid / entry_label target one entry of a list-mode item) or file_id (an uploaded spreadsheet parsed server-side, each row classified with the model's mapping rules; sheet_name, structure_override, replace_source_id refine the parse). An entry's timeline_ref equals the target item's grain or constant (any other grain is rejected); on a formula / balance it is a per-period override; on a callup it lands on the source (redirected). A data source is materialized on the file_id path and when record_import is given; bare entries[] write a manual overlay with no source. replace: true (with branch.id) wipes the branch's rows before writing, uncovered periods keeping their prior value; merge: true upserts cell by cell; dry_run: true returns the impact (would_persist: false, overridden_items, validation_errors_new) without persisting. Returns dataset_id, created_items, matched_items, entries_written, inputs_written, inputs_removed, warnings (plus skipped, mapping_drift, file_structure on the file path). Persists one version labelled with summary. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
mergeNo
branchYes
dry_runNo
entriesNo
file_idNoUpload id from layerz_create_upload_url ('f_' + 16 hex chars). Alternative to entries[].
replaceNo
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.
sheet_nameNo
record_importNo
replace_scopeNo
replace_source_idNofile_id path only: refresh this existing file source in place (id from layerz_list_integrations) instead of creating a second one.
structure_overrideNoOverride auto-detected columns for a long-format/ledger file (e.g. value_column chose "Débit" and dropped credit rows, or an account-code column won the label). Omitted fields stay auto-detected.

TDQS

A4.2/5.0
Behavior5/5

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

Annotations already flag destructiveHint=true and readOnlyHint=false, and the description adds substantial context beyond that: replace wipes the branch's rows while uncovered periods keep prior values, merge upserts cell by cell, dry_run returns impact without persisting, a version is persisted and labelled with summary, and the tool is not advertised to read-only keys. That is exactly the destruction/scope/permission detail an agent needs on 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?

Every sentence carries information - source exclusivity, timeline_ref rules, materialization, replace/merge/dry_run, return fields - and the core action is front-loaded. It is delivered as one very long paragraph however, and the lack of any break between the source discussion and the write-mode discussion makes it harder to scan than it needs to be for a 13-parameter tool.

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

Completeness4/5

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

With no output schema, the description correctly enumerates the return payload (dataset_id, created_items, matched_items, entries_written, inputs_written, inputs_removed, warnings, plus file-path-only fields), which is the right use of the space. Auth behavior and version persistence are also covered; the main omission is replace_scope, which is an enumerated parameter left unexplained in both description and schema.

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?

Schema description coverage is only 38% across 13 parameters, but the description compensates heavily, explaining branch.id/display_name/actuals_through, entries[] resolution via item_uid/item_label, entry_uid/entry_label list-mode targeting, timeline_ref grain constraints, file_id, sheet_name, structure_override, replace_source_id, and record_import. Gaps remain: replace_scope ('branch' vs 'import'), branch.priority, branch.source_hint, and branch.file_name are never explained.

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

Purpose4/5

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

The first clause names a specific verb and resource ('Writes values onto a branch of the model') and immediately clarifies the create-if-absent behavior, so the agent knows exactly what the tool does. It does not, however, name or distinguish itself from close siblings such as layerz_parse_file, layerz_patch, or layerz_validate_model, so the routing value stops short of a 5.

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?

Mode selection is well covered: 'Two sources, mutually exclusive' explains when to use entries[] vs file_id, and the description explains when replace, merge, and dry_run apply and what each does. What is missing is guidance on choosing this tool over sibling tools (e.g. layerz_parse_file for inspection, layerz_validate_model for checks), so there are no explicit alternatives or exclusions.

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

layerz_list_integrationsList data sources
Read-only
Inspect

Lists every data source feeding a model: API connectors (Qonto, Pennylane, Stripe, Airtable, Metabase) and file imports (kind csv | fec), each with kind, display_name, branch_ids (the branches it feeds), sync status, last_synced_at and source_fields (the payload fields an API connector's field_map can re-point its description / category / account_number to; null when there is nothing to choose). A row with legacy_import_id is a materialized pre-staging import that owns input rows but staged no transactions. include_external_refs: true adds external_refs: the links to items of other Layerz models, each with a value-aware stale flag (the source moved in a way that changes the snapshot) and its source health. Stored credentials are not returned.

ParametersJSON Schema
NameRequiredDescriptionDefault
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
include_external_refsNoAlso return the external references (links to other models) with their staleness.
layerz_list_mappingsList mapping rulesA
Read-only
Inspect

Lists the import classification rules in scope for a model: sets (each with a scope: model = the model's own rules, system_template = the curated country catalogs (PCG, US GAAP, UK, SKR03/04), user_template = the caller's reusable catalogs), mappings (the effective rules: pattern → target item, sign, source scope) and templates (the catalogs importable through layerz_manage_mapping { op: "import_template" }). A model classifies with its own model rules only; a catalog applies once imported. A pattern is a case-insensitive glob where * matches anywhere. include_user_mappings: true adds the account-wide catalogs to sets / mappings; include_coverage: true adds per-rule match_count and a coverage block (auto-created count, ignored count, the top keys routing nowhere).

ParametersJSON Schema
NameRequiredDescriptionDefault
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
include_coverageNoAlso compute `match_count` per rule and a `coverage` block (classifies every source: heavier read).
include_user_mappingsNoAlso list the account-wide user catalogs in `sets` / `mappings` (default: only what the model classifies with).

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered; the description adds the behavioral cost disclosure that `include_coverage` is a heavier read. It also explains the semantics of the returned sets (which rules are actually effective) and glob matching, though it says nothing about ordering or result size limits.

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?

Purpose is front-loaded in the first clause, and the parenthetical breakdowns of `scope` values and flag effects are informative rather than filler. It is a single dense block, however, and the backtick-heavy detail makes it heavier than a list tool strictly needs.

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?

With no output schema, the description must carry the return-shape burden, and it does: it names the collections to expect and their contents, explains `scope` semantics, glob matching rules, and what the optional coverage block contains. Nothing essential for calling or interpreting this read tool is missing.

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

Parameters3/5

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

Schema description coverage is 100%, and the tool has only 3 optional params, so the baseline is 3. The description's flag explanations largely restate the schema descriptions (account-wide catalogs, coverage match counts) rather than adding new syntax or constraints beyond them.

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?

States a specific verb (lists) and resource (import classification rules in scope for a model), then enumerates the three returned collections (`sets`, `mappings`, `templates`) with what each contains. It also distinguishes itself from `layerz_manage_mapping` by naming the import_template op that acts on catalogs, so an agent can separate listing from mutation.

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?

Explains the conditions under which each flag matters (`include_user_mappings: true` widens to account-wide catalogs; `include_coverage: true` adds per-rule counts and a coverage block) and clarifies that a model classifies only with its own `model` rules until a catalog is imported. It doesn't explicitly state when-not-to-use or name a read alternative like `layerz_list_templates`, so it falls short of full routing guidance.

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

layerz_list_modelsList modelsA
Read-only
Inspect

Lists the models the authenticated user can access. Each entry carries can_write (owner or editor), url, glyph and sharing: { shared, member_count, link_visibility }. q filters by name (case-insensitive substring, * wildcard), writable: true keeps owner/editor models only. A model-scoped key gets its bound model only.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoName filter: case-insensitive substring ("swoop" matches "SWOOP - BP 2026"); `*` is a wildcard, `%`, `_` and `&` are literal.
writableNoWhen true, only models the caller can edit (owner or editor).

TDQS

A3.8/5.0
Behavior4/5

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

The annotations already declare a safe read (readOnlyHint=true, destructiveHint=false). Beyond that, the description discloses the return structure (can_write, url, glyph, sharing) and the edge case that a model-scoped key returns only its bound model — real context not present in annotations.

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?

A single dense paragraph, front-loaded with the purpose and then the filter and edge-case details. Every sentence carries information, with no filler, though the packing of field names is slightly dense.

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

Completeness4/5

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

With no output schema, the description usefully spells out the returned entry fields and the scoped-key caveat, and annotations cover the safety profile. Pagination, ordering, and total-count behavior are unaddressed but are minor for this read tool.

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?

Schema coverage is 100%, so the schema already documents both parameters, establishing a baseline of 3. The description adds value by noting that a model-scoped key ignores the filters and returns only the bound model, refining the semantics of `q` and `writable` beyond the schema.

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

Purpose4/5

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

The description states a specific verb and resource ('Lists the models') plus scope ('the authenticated user can access'), and enumerates the entry fields. It never explicitly names a sibling like layerz_get_model to contrast single-vs-list retrieval, so it is clear but not sibling-differentiating.

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

Usage Guidelines3/5

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

Filtering behavior is explained (`q` for name, `writable: true` for owner/editor), which implicitly guides usage, and the model-scoped-key note is a useful conditional. However, there is no explicit when-to-use-this-vs-alternatives guidance relative to get_model or the other list_* siblings.

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

layerz_list_templatesList templatesA
Read-only
Inspect

Lists the reusable model templates: the curated system catalog and the caller's own user templates. Each entry carries name, subtitle, glyph, description (the template's FINANCE.md, its usage guide), category, scope and a structure summary (section names + item count). With template_id, returns that single template in full, blueprint included. A template forks into a new model through layerz_create_model { template_id } and applies as a module through layerz_build_from_blueprint { template_id }.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNoScope filter: "system" (curated) or "user" (own templates).
template_idNoOne template in full (blueprint + usage guide) instead of the list.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare a safe read (readOnlyHint=true, destructiveHint=false, openWorldHint=false). The description adds real context beyond that: it enumerates each entry's fields (name, subtitle, glyph, description, category, scope, structure summary) and notes that `template_id` switches to a full single-template return including the blueprint. No pagination or size limits are mentioned, keeping it below a 5.

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

Conciseness5/5

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

Two dense sentences, front-loaded with what is listed before describing entry contents and downstream usage. No filler; every clause carries 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 read-only listing tool with no output schema, the description covers the enumeration scope, per-entry field contents, the single-retrieval mode, and the follow-up tools to act on a template. Nothing an agent needs to call it correctly is missing.

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?

Schema description coverage is 100%, so the baseline is 3. The description adds meaning beyond the schema by clarifying that `template_id` returns that single template 'in full, blueprint included' and by framing `scope` as the system-vs-user distinction, which is more than a restatement of the field docs.

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?

States a specific verb (Lists) and resource (reusable model templates), and distinguishes the two sub-scopes (`system` curated vs caller's `user` templates). It also clarifies the two operational modes — list vs single-template retrieval via `template_id` — so an agent can tell exactly what the tool does without opening the schema.

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?

Explicitly routes the agent downstream: fork through `layerz_create_model { template_id }` and apply as a module through `layerz_build_from_blueprint { template_id }`. That is strong alternative/next-step guidance, though it doesn't state a when-not condition (e.g. when to prefer this over `layerz_list_models`).

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

layerz_list_transactionsList staged transactionsA
Read-only
Inspect

Returns a data source's staged transactions (API connector or csv/fec file import) annotated with their routing: the target item and whether a rule or an auto-created item matched, the skip reason otherwise (mapping is the only routing path, no fuzzy match), or ignored for a row an __ignore__ rule routes nowhere on purpose. period (YYYY-MM) and q (substring on description/category) filter the rows. format: 'csv' returns instead a 24h signed download_url of the full staged import as a CSV file (no filters, no annotations). A materialized legacy import derives one row per owned cell from the model's input rows.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoKeeps rows whose description/category contains this text.
formatNojson (default): annotated rows inline. csv: a signed `download_url` of every staged row as a CSV file.
periodNoKeeps only this YYYY-MM period.
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
connection_idYesSource id as returned by layerz_list_integrations.

TDQS

A4.6/5.0
Behavior5/5

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

With readOnlyHint already covering the safety profile, the description still adds rich context: csv mode returns a 24h signed download_url of the FULL import with no filters or annotations, mapping is the only routing path (no fuzzy match), __ignore__ rules yield 'ignored', and legacy materialized imports derive one row per owned cell. These are behavior traits annotations cannot express.

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-loads what is returned, then layers in filtering, the csv variant, and the legacy edge case. It is a dense single paragraph where each clause carries information, though the wall-of-text density slightly hurts scanability.

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?

With no output schema, the description carries the full burden and does so: it describes annotated rows, the routing labels (rule/auto/skip reason/ignored), the csv download_url shape, and the legacy-import row derivation. An agent has enough to call and interpret it correctly.

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?

Schema coverage is 100% (baseline 3), but the description adds meaning beyond the schema: period is YYYY-MM, q matches description/category substrings, and csv format deliberately ignores filters while json annotates inline. The interplay between format and the other filters is not obvious from the schema alone.

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: returns a data source's staged transactions, then immediately scopes them as 'annotated with their routing'. It distinguishes itself from siblings like layerz_list_mappings and layerz_list_integrations by clarifying that this lists the staged rows themselves, not the mapping definitions.

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?

Explains how period and q filter rows and when format:'csv' applies (full import, no filters, no annotations), which routes the agent between the two modes. It does not explicitly name an alternative tool or state when-not-to-use, so it stops short of a 5.

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

layerz_manage_integrationSync, configure or delete data source
Destructive
Inspect

Runs one operation on a data source (API connector Qonto, Pennylane, Stripe, Airtable, Metabase, or a csv/fec file import) by op. sync: pulls the provider's rows into the bound branch as a replace of this source's own rows (the baseline is untouched); on a file source, replays the projection over the staged rows; target_branch_id lands a still-unbound connection on an existing branch; dry_run: true reports the impact without persisting. rebind: re-points the source at branch_ids, wiping its rows from detached branches and reprojecting into the new ones. update: renames the source (display_name) and/or applies config then replays the projection; a change of import_level or of a tabular mapping (field_map, measures, sign_rule) re-fetches and re-stages, and is rejected on a csv/fec file source. delete: disconnects the source, drops its staged transactions and purges everything it projected into the model (input rows, provenance, import entry); items and the branch are kept, emptied; when the purge would destroy values the source cannot re-project, the call is refused with PURGE_CONFIRMATION_REQUIRED and a purge_preview, and a retry with confirm_purge: true performs it. Every projecting op returns unmapped, proposed_window, deletable_items (reported, not removed), cutover_changes, shadowed, warnings. Credentials stay in the web app. Persists one version labelled with summary. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
opYesOperation to run on the source.
configNo`update` only: non-secret import config to apply.
dry_runNo`sync` only: reports the impact without persisting.
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.
branch_idsNo`rebind` only: the existing branches the source feeds afterwards (e.g. ["default"]).
display_nameNo`update` only: new label of the source (metadata, no reprojection).
confirm_purgeNo`delete` only: confirms the purge after a `PURGE_CONFIRMATION_REQUIRED` refusal.
connection_idYesSource id as returned by layerz_list_integrations.
target_branch_idNo`sync` only: existing branch a still-unbound connection feeds (e.g. `default`). Ignored once bound.
layerz_manage_mappingSet, delete or import mapping rulesA
DestructiveIdempotent
Inspect

Writes the model's classification rules by op, in its single mapping set (created on first use). set: creates or updates rules identified by (source_id, pattern, secondary_pattern), one rule from the flat fields or up to 500 in rules (one form per call). pattern is a case-insensitive glob where * matches anywhere (Apport*, *641, 601000) tested against the source's primary key; secondary_pattern (default *) against its secondary key; source_id scopes the rule to one source (omitted = model-wide; a scoped rule wins on its source); target is an item name or uid, uid::entryUid for one entry of a list-mode item, or __ignore__ to route matching rows nowhere; sign (natural | negate | absolute) adjusts the amount. The batch is validated whole first (empty pattern, foreign source, target matching no item or several, repeated key): one failure writes nothing. Each rule reports created, updated or unchanged, with totals; a replay writes nothing. delete: removes mapping_id, or every id of mapping_ids (up to 500). import_template: duplicates the rules of the catalog template_id into the model set, targets translated by item name; a conflicting imported rule overwrites the model's, reported in overwritten. A rule change applies to the projected values on the next layerz_manage_integration { op: "sync" }. Rules live outside the model snapshot: no version is written, summary labels the call. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
opYesOperation to run on the rules.
signNoSign convention applied to the matched amount (default natural).
rulesNo`set`: up to 500 rules written as one batch, in place of the flat fields.
targetNoTarget item name or uid; `uid::entryUid` pins one list entry; `__ignore__` routes nowhere on purpose.
patternNoPrimary key glob (`*` anywhere) or exact value.
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.
source_idNoScopes the rule to one data source of the model (id from layerz_list_integrations). Omitted = model-wide.
mapping_idNo`delete`: rule id from layerz_list_mappings.
mapping_idsNo`delete`: up to 500 rule ids removed as one batch.
template_idNo`import_template`: catalog set id from layerz_list_mappings `templates`.
secondary_patternNoSecondary key glob tested against the source's `dimension_by` field (default `*` = any).

TDQS

A4.6/5.0
Behavior5/5

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

Far exceeds the annotations: whole-batch validation semantics ('empty pattern, foreign source, target matching no item or several, repeated key' → nothing written), per-rule created/updated/unchanged status with totals, replay writes nothing, import overwrite behavior with `overwritten`, and the fact that no version is written though `summary` labels the call. These are non-obvious consequences an agent must know.

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 operation summary before per-op detail, and every sentence carries load-bearing information. It is dense and long, but the 12-parameter/3-op complexity justifies most of it; a few parenthetical lists could tighten.

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?

With no output schema, the description carries the return contract (created/updated/unchanged, totals, overwritten) and the side-effect/versioning story. Given the tool's complexity, an agent has everything needed to call it correctly.

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?

Schema coverage is 100% (baseline 3), but the description adds genuine meaning: glob semantics for `pattern` vs `secondary_pattern` with examples, source scoping precedence ('a scoped rule wins on its source'), target forms (`uid::entryUid`, `__ignore__`), and the mutual exclusivity of flat fields vs `rules` ('one form per call').

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?

The description opens with a specific verb+resource ('Writes the model's classification rules by `op`') and immediately enumerates the three operations with concrete scope. An agent can distinguish this from layerz_list_mappings and layerz_manage_integration without opening the schema.

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?

It clearly states what each `op` is for and names the flow ('a rule change applies to the projected values on the next layerz_manage_integration { op: "sync" }'), plus the read-only-key exclusion. It does not explicitly contrast against siblings beyond pointing at list_mappings/list_integrations for ids, so it stops short of full when/when-not routing.

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

layerz_manage_versionPin, unpin or restore versionA
DestructiveIdempotent
Inspect

Acts on one version of a model (version: exactly one of revision_id, version_number, id) by op. pin: keeps the version listed, diffable and restorable beyond the plan history window; capped per plan (max_pinned_versions, 403 past the cap); a no-op on a pinned version. unpin: frees the slot; a version past the window then stops being listed. restore: replaces the live items, schema and inputs with that snapshot, after saving the current state as a restore backup version (backup_version_id, null when the live state already matched the latest snapshot); requires summary, the label of the restored state. Returns { ok, version_id, version_number, revision_id, pinned, pinned_count, max_pinned_versions } for pin / unpin, { ok, restored_version_id, restored_version_number, restored_revision_id, backup_version_id } for restore. The target is inside the plan window or pinned. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
opYespin | unpin | restore.
summaryNoRequired with `restore`: label of the restored state in the history.
versionYesTarget version: exactly one of revision_id / version_number / id.
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.

TDQS

A4.6/5.0
Behavior5/5

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

Annotations only say non-read-only, destructive and idempotent; the description goes well beyond that by disclosing the pin cap with a 403 failure mode, the no-op on an already-pinned version, the fact that restore overwrites live items/schema/inputs after writing a `restore` backup, the `backup_version_id: null` edge case, and the read-only-key visibility rule.

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?

Dense but front-loaded: the target and op come first, then per-op semantics, then return shapes. Every sentence carries information, though the run-on packing of return fields is slightly hard to scan.

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 destructive, nested-parameter mutation with no output schema, the description is complete: it covers targeting rules, per-op side effects, error conditions (403 cap), required inputs, visibility, and both return shapes. An agent has everything needed to invoke it correctly.

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?

Schema coverage is already 100%, so the baseline is 3. The description still adds value by tying conditional requirements to ops (`summary` only with `restore`, `version` being exactly one identifier form) and by explaining that `model_id` is validated against a bound model for model-scoped keys, which clarifies requiredness beyond the schema text.

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?

The description states a specific verb set (pin/unpin/restore) acting on a precisely scoped resource (one version of a model) and names the three mutually exclusive identifiers accepted. No sibling tool overlaps, and an agent can distinguish this from layerz_history, layerz_diff or layerz_get_model without opening the schema.

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?

Each `op` is given a clear effect and condition: `pin` for retaining beyond the history window, `unpin` to free the slot, `restore` to roll live state back (with `summary` mandatory). It also states the target must be in-window or pinned and that the tool is hidden from read-only keys. It stops short of an explicit when-to-prefer-this-over-alternatives statement, but per-op semantics effectively cover selection.

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

layerz_match_itemsMatch labels to itemsA
Read-only
Inspect

Resolves free-text labels (e.g. row labels of a parsed file) to existing item UIDs of a model: the top 3 candidates per label across exact_uid, exact_name, slug and fuzzy (Levenshtein) methods, each with a score. An empty candidate list means no existing item matched. Deterministic, no LLM call.

ParametersJSON Schema
NameRequiredDescriptionDefault
labelsYesFree-text labels to resolve.
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and non-destructive, so the safety profile is covered. The description adds genuinely useful behavior: determinism ('no LLM call'), the candidate-per-label cap of 3, the scoring, and the meaning of an empty candidate list. It omits any note on ordering or score range, keeping it short of a 5.

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?

Two tightly packed sentences with the purpose front-loaded and zero filler. The parentheticals and clause list make it dense but still readable; nothing is wasted.

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

Completeness4/5

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

With no output schema, the description carries the return-value burden and does it well: candidate count, methods, scoring, and empty-list semantics are all stated. Minor gaps remain (score scale, ranking order), but an agent has enough to call and interpret it.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents both parameters, including model_id's scoping rules. The description clarifies what a label resolves to and the result shape per label, but adds little parameter-level meaning beyond the schema, matching the baseline 3.

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?

States a precise verb+resource: resolving free-text labels to existing item UIDs of a model. It further specifies the mechanics (top 3 candidates across exact_uid, exact_name, slug, and Levenshtein fuzzy matching, each scored), which no sibling tool does, so an agent can distinguish it from layerz_parse_file or layerz_validate_model immediately.

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?

Anchors the use case concretely with 'e.g. row labels of a parsed file,' implying this follows a parse step and precedes item creation/update. It does not name explicit alternatives or exclusions, so it falls short of a full when-to-use/when-not statement.

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

layerz_parse_fileParse uploaded fileA
Read-only
Inspect

Parses an uploaded Excel/CSV (file_id) deterministically and returns a token-optimized structure: sheet summaries (without sheet_name) or, for one sheet, the detected timeline, suggested_structure (layout, header row, columns), row labels and column headers with samples. A wide sheet is recognised by its period header: a run of at least three consecutive periods (bare years such as 2026, YYYY-MM, Jan 2026, Q1 2026, date cells) in any column, reported as detected_periods and period_range. A raw DATEV EXTF export is detected natively. structure_override re-parses with corrected columns when a ledger is misdetected (a Débit column taken as the value, an account-code column taken as the label) or when a wide sheet has fewer than three period columns (layout: "wide"). The raw binary is not returned.

ParametersJSON Schema
NameRequiredDescriptionDefault
file_idYesUpload id as returned by layerz_create_upload_url ('f_' + 16 hex chars).
sheet_nameNoSheet of a multi-sheet workbook. Omitted: sheet summaries only.
structure_overrideNoOverride auto-detected columns for a long-format/ledger file (e.g. value_column chose "Débit" and dropped credit rows, or an account-code column won the label). Omitted fields stay auto-detected.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds genuine behavior beyond that: deterministic parsing, native DATEV EXTF detection, the period-header heuristic, re-detection rules on override, and the explicit note that the raw binary is not returned.

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?

It is a single dense paragraph but front-loads the core purpose and return shape before the detection and override details. Nearly every clause carries information, though the period-format enumeration and parenthetical examples make it heavier than strictly necessary.

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

Completeness4/5

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

For a complex tool with a nested `structure_override` object and no output schema, the description names the key returned artifacts (sheet summaries, `detected_periods`, `period_range`, `suggested_structure`) and covers the main detection/override behaviors. Minor gaps remain on full response shape and error conditions, but the agent has enough to call it correctly.

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?

Schema description coverage is 100%, so the baseline would be 3. The description rises above it by explaining the intent behind parameters—why `structure_override` exists (Débit taken as value, account-code taken as label, wide sheets with too few period columns) and what omitting `sheet_name` produces.

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?

The description states a specific verb and resource ('Parses an uploaded Excel/CSV (`file_id`) deterministically') and immediately names what it returns, which sharply separates it from the write-side sibling `layerz_import_branch`. An agent can tell this is the inspect/parse step versus an import.

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

Usage Guidelines3/5

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

It gives conditional guidance for parameters (omit `sheet_name` for summaries only; use `structure_override` when a ledger is misdetected or a wide sheet has <3 period columns). However, it never states when to reach for this tool versus alternatives such as `layerz_import_branch`, leaving tool-level selection to inference.

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

layerz_patchApply model patch
Destructive
Inspect

Applies a batch of mutations to a model: create, replace, update, delete, move, list_create, list_update, list_delete and meta (name, subtitle, finance_md, timelines, formats, number_locale, default_branch, glyph). The batch is all-or-nothing: a validation failure persists nothing and returns every error at once (MODEL_VALIDATION_ERROR, details[]). A create may carry a temp id that later ops of the batch reference (parent, source, target, series, liste_ref, after, $_id in a formula); the result map gives each temp id its UID. replace keeps the item's UID and presentation fields; update is a strict partial merge of the named fields. Root accepts section and dashboard; dashboard accepts widgets only; a formula with both an expression and children is rejected (FORMULA_EXPR_AND_CHILDREN); a list-mode item takes timeline_values and rejects value / values; a non-list item takes value / values (a sparse period-keyed timeline_values map merges into values). branch_id routes the value writes onto that branch as an overlay of the cells differing from the base, with no data source; compute returns the computed series of the given UIDs (under compute_branch, default branch_id); dry_run validates and computes without persisting. Persists one version labelled with summary. Not advertised to read-only keys. Modeling patterns and examples: resource modeling-guide://reference.

ParametersJSON Schema
NameRequiredDescriptionDefault
opsYesMutation operations. Each op is a discriminated object on a string `op` field (e.g. {op:'create', role:'assumption', name:'Revenue'}; {op:'replace', from_uid:'abc', new_item:{role:'formula', name:'Revenue', formula:'xyz * 12'}}; {op:'update', uid:'abc', value:42}).
computeNoUIDs to compute after mutations
dry_runNoValidates and computes the batch without persisting it.
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.
branch_idNoBranch that receives the value writes of this batch (`update` / `replace` `value`, `values`, `timeline_values` on assumptions): only the cells that differ from the base are stored as that branch's overlay, the same record a value edit makes in the web editor with the branch checked out; no data source is created. Absent or `default`: the base plan. Structural ops and non-value fields apply to the model as a whole; a `create` carrying values under a branch is rejected. An unknown id is rejected.
compute_branchNoBranch whose `[base, branch]` checkout the `compute` values are returned under, instead of the stacked-all view (mirror of `layerz_read` `branch_id`); `default` = the base plan alone. Defaults to `branch_id` when that is set. Requires `compute`.
layerz_promote_templatePromote model to templateA
Idempotent
Inspect

Promotes a model the caller owns into a reusable template in place: no copy, the model keeps its content and stays editable, and it appears in layerz_list_templates. Its usage guide is the model's FINANCE.md. scope: 'user' (default) is private and Pro-gated; scope: 'system' publishes into the curated catalog visible to every account and is admin-only. Not advertised to model-scoped or read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesTemplate title; renames the model in place when it differs.
scopeNo`user` (default): private, owner-only, Pro-gated. `system`: curated public catalog, admin-only.
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.
descriptionNoUsage guide (FINANCE.md). The model keeps its own when omitted.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations only declare the generic safety profile (non-read-only, non-destructive, idempotent, open-world); the description adds the in-place mutation semantics, that content is preserved and stays editable, the publish-visibility consequence of `system` scope, and permission gating. These are exactly the traits an agent needs before invoking a mutation and are not derivable from the annotations.

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

Conciseness5/5

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

Dense but front-loaded: the in-place nature comes first, then discoverability, then scope/permission constraints. Every clause carries a distinct fact (no copy, editable, list visibility, scope gating, key-type exclusion) with no filler.

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 mutation tool with no output schema, the description covers side effects, reversibility implications (content preserved), visibility changes, auth requirements, and key-scope exclusions. An agent has everything needed to decide and call correctly.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: it identifies the `description` field as the model's FINANCE.md usage guide that is kept when omitted, and characterizes what `system` scope actually does (curated public catalog). The rest largely restates the enum descriptions.

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?

States a specific verb+resource ('promotes a model ... into a reusable template in place') and immediately distinguishes itself from copy-based alternatives by clarifying no copy is made and the model stays editable. The mention of `layerz_list_templates` gives an agent a concrete downstream effect to recognize.

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?

Explains the conditions that select each scope: `user` = private and Pro-gated, `system` = curated catalog and admin-only, plus an explicit exclusion ('Not advertised to model-scoped or read-only keys'). It stops short of naming when to promote in place versus building a separate template from a blueprint, so it is strong context rather than full alternative routing.

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

layerz_readRead model snapshotA
Read-only
Inspect

Returns a UID-native snapshot of a model: model (name, timelines, lists, branches), items (flat, parent_uid carries the hierarchy, each with role, formula, check, note) and revision_id / version_number. Filters: uids, roles, include_children. with_values: true adds the computed series v aligned with the periods p (periods for explicit labels of mixed grains, else granularity), variance adds vv, per_element adds ve for list-mode items, health adds the check report, branch_id computes v and health under one branch's [base, branch] checkout instead of the stacked view. The check report is judged on a branch checkout, not the stacked view: without branch_id, a multi-branch model reports the branch it opens on (health.branch_id) and every branch under health.by_branch. When the response leads with computable: false, errors[] names the broken dependencies (e.g. CIRCULAR_DEPENDENCY) and every series is a zero-filled placeholder.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsNoFilter by item UIDs
rolesNoFilter by role
healthNoAlso returns the `health` block: non-blocking check violations (lines flagged `check`), evaluated at the finest active grain under a branch checkout rather than the stacked view: the `branch_id` requested, else on a multi-branch model the branch the model opens on (`health.branch_id`) with every branch's verdict under `health.by_branch`. `with_values: true` already includes `health` when the model has checks; this flag returns `health` without the full value series.
periodsNoPeriod labels to scope values to
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
varianceNoAlso return the variance series `vv` (stacked-all view − base baseline), aligned with `v`. Requires with_values.
branch_idNoBranch whose `[base, branch]` checkout the values `v` and the check report `health` are computed under, instead of the stacked-all view (base-vs-overlay audit); `default` = the base plan alone. An unknown id is rejected. Requires with_values or health.
granularityNoGrain for `v`/`p` when no explicit `periods` are given. 'native' = finest active dated grain (monthly>quarterly>yearly). Default: 'yearly'. Ignored when `periods` are provided (each label resolves its own grain).
per_elementNoAlso return `ve`: per-element series for list-mode items, keyed `ve[itemUid][elementLabel]` and aligned with `p` (e.g. payroll split by Business Unit). Without it, `v` only carries the aggregate. Requires with_values.
with_valuesNoCompute and return values for matched items
include_listsNoWhich named lists to embed in `model.lists`: 'referenced' (default — only lists used by the returned items via liste_ref), 'all', or 'none'.
include_childrenNoInclude descendants of filtered containers

TDQS

A3.9/5.0
Behavior5/5

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

Annotations already declare readOnlyHint/destructiveHint=false, and the description still adds substantial behavior: the branch-checkout vs stacked-view distinction for health, the multi-branch health.branch_id / health.by_branch fallback, rejection of unknown branch ids, and the failure contract where computable:false pairs errors[] (e.g. CIRCULAR_DEPENDENCY) with zero-filled placeholder series. That is exactly the kind of beyond-annotation context this dimension rewards.

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

Conciseness3/5

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

Content is dense but load-bearing, and the return-shape sentence is correctly front-loaded ahead of the flag semantics. It is nonetheless one undivided wall of text with heavily nested clauses, and the health/branch material is duplicated nearly verbatim from the schema, so it is not efficiently structured.

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?

With no output schema, the description carries the full burden of describing returns and does so thoroughly: top-level keys, series naming (v, p, vv, ve), health evaluation semantics, and the error/degraded-computation path. An agent can predict the response shape and failure mode without any other source.

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

Parameters3/5

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

Schema description coverage is 100% and the schema text is itself verbose (branch_id, health, per_element, granularity all carry their own detailed descriptions), so the schema already does the heavy lifting. The prose largely restates those same semantics rather than adding new ones, which lands at the documented baseline of 3.

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

Purpose4/5

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

The opening clause gives a concrete verb and resource ('Returns a UID-native snapshot of a model') and enumerates the payload shape (model, items, revision_id/version_number), so the agent knows exactly what comes back. It never distinguishes itself from the sibling layerz_get_model or explains which read tool to pick, leaving that gap against a crowded read-side family.

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

Usage Guidelines3/5

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

The description gives strong intra-tool conditions ('variance requires with_values', 'branch_id requires with_values or health', 'granularity ignored when periods are provided'), which is real conditional guidance. It offers no when-to-use versus alternatives, however: nothing tells the agent when to choose layerz_read over layerz_get_model, layerz_diff, or layerz_dependencies.

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

layerz_set_custom_instructionsSet custom instructionsA
DestructiveIdempotent
Inspect

Replaces the user's account-wide custom instructions for AI agents (plain Markdown/text, ≤ 3000 chars; an empty string clears them). They apply across every model, on top of each model's FINANCE.md, and are delivered in the handshake instructions of the next session. No version is persisted. Not advertised to model-scoped or read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYesAccount-wide custom instructions, max 3000 chars. Empty string clears them.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare destructive=true and idempotent=true, so the safety profile is covered; the description adds genuinely new behavior: delivery happens in the next session's handshake, no version is persisted (no rollback), and the tool is not exposed to model-scoped or read-only keys. This auth/visibility and delivery context exceeds what annotations provide, though reversibility could be stated more directly.

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

Conciseness5/5

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

The core action is front-loaded in the first clause, followed by format, length, clearing semantics, scope, delivery, persistence, and access constraints. Every sentence carries distinct information with no padding.

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 single-parameter setter with no output schema, the description covers format, size limit, clearing behavior, scope of effect, when changes take effect (next session), persistence, and key visibility. Nothing an agent needs to invoke it correctly is missing.

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

Parameters3/5

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

Schema coverage is 100% and the single 'content' parameter already documents the 3000-char max and empty-string clearing behavior, both of which the description simply restates. With one well-documented parameter, the baseline of 3 applies as no additional meaning is added.

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?

States a specific verb (Replaces) and resource (account-wide custom instructions) with explicit scope, and the scope wording ('account-wide', 'apply across every model') distinguishes it from the model-scoped sibling layerz_set_finance_md. An agent can identify the operation without opening the schema.

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?

Clarifies the clearing case ('an empty string clears them') and implicitly contrasts its scope with a model's FINANCE.md, which differentiates it from the finance sibling. However, it never explicitly states when to prefer this over siblings like set_finance_md or get_conventions, leaving selection partly to inference.

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

layerz_set_finance_mdSet FINANCE.mdA
Idempotent
Inspect

Replaces the FINANCE.md attached to a model with the given Markdown (YAML front matter + body, ≤ 5,000 chars). source: 'imported' marks content synced from a project-root file, 'user' (default) content authored in place. The content parses as a YAML front-matter document; schema warnings are returned without blocking. On a template, this FINANCE.md is its usage guide, so the edit reaches every account that reads the template. Persists one version labelled with summary. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
sourceNoProvenance: 'imported' (synced from a project-root FINANCE.md) or 'user' (default).
contentYesFull FINANCE.md Markdown (YAML front matter + body), max 5,000 chars.
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.

TDQS

A4.1/5.0
Behavior5/5

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

Beyond the annotations (idempotentHint, destructiveHint=false, openWorldHint), the description discloses real behavioral traits: the prior content is replaced but a labelled version is persisted, schema warnings are returned without blocking the write, and on a template the edit propagates to every account reading it. It also notes the tool is not advertised to read-only keys, which annotations alone do not express.

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?

Dense but front-loaded: the replacement action and payload constraints come first, followed by provenance, validation behavior, and blast radius. Every sentence carries information, though the length approaches the point where scanning cost rises.

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

Completeness4/5

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

For a mutation tool with no output schema, the description covers the write behavior, version persistence, non-blocking validation warnings, and template-wide impact, leaving little an agent must infer. The only minor gap is that the model_id requirement for user-scoped keys is left to the schema.

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

Parameters3/5

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

Schema coverage is 100%, so the baseline is 3. The description restates the 'source' enum meanings, the 5,000-char limit, and that 'summary' labels the persisted version — all already documented in the schema, so it adds little beyond what structured fields provide.

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?

The description gives a precise verb and resource ('Replaces the FINANCE.md attached to a model') plus the payload shape (YAML front matter + body, ≤5,000 chars), which is concretely distinguishable from generic siblings like layerz_read. It also clarifies the template-scoped consequence, making the scope clear without opening the schema.

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

Usage Guidelines3/5

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

Usage context is implied through the 'source' semantics and the template-propagation note, but there is no explicit when-to-use / when-not-to-use guidance and no routing to alternatives such as the sibling that sets custom instructions. Adequate but with clear gaps in decision guidance.

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

layerz_share_modelInvite or revoke model accessA
Destructive
Inspect

Changes who can access a model, by op. invite (default): grants email the role viewer (read-only, default) or editor; a registered user gets an active share, an unregistered one a pending invite; both receive an email. revoke: removes the collaborator or pending invite principal_id (an id from the sharing.members of layerz_get_model). Owner-only. The link visibility (invite / public) is changed by the owner in the web app only. No version is persisted. Not advertised to read-only keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
opNoinvite (default) | revoke.invite
roleNo`invite`: viewer (read-only, default) or editor.
emailNo`invite`: the email address to invite.
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.
principal_idNo`revoke`: collaborator user id or pending-invite id from `sharing.members`.

TDQS

A4.9/5.0
Behavior5/5

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

Goes well beyond the annotations (destructiveHint/openWorldHint only flag risk): it discloses owner-only authorization, that a registered vs unregistered invitee produces an active share vs a pending invite, that an email is sent, that no version is persisted, and that the tool is not advertised to read-only keys.

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

Conciseness5/5

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

Extremely dense yet well-ordered: operation modes first, then authorization and side effects, then constraints. Every clause carries operational information with no filler.

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 5-param mutation with no output schema and only terse annotations, this covers the essentials an agent needs: mode branching, permissions, side effects, and where the revoke identifier originates. Nothing material is left to inference.

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?

Schema coverage is already 100%, but the description still adds value: it ties `role`/`email` to the `invite` branch, `principal_id` to the `revoke` branch, and explains that `principal_id` comes from `sharing.members` of `layerz_get_model`. It stops short of adding format or edge-case detail beyond the schema's enum/pattern constraints.

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?

States the specific verb pair (invite/revoke via `op`) and the exact resource it mutates: model collaborator access. It is clearly distinguishable from siblings like `layerz_get_model` (read) and `layerz_manage_version`, and even names `layerz_get_model` as the source of `principal_id`.

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

Usage Guidelines5/5

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

Explicitly separates the two modes: `invite` (default) grants viewer/editor and mails the user; `revoke` removes a collaborator or pending invite. It also states the owner-only precondition, the `model_id` scoping rule, and that link visibility cannot be changed here, routing the agent elsewhere.

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

layerz_update_branchCreate or update branchA
Idempotent
Inspect

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 (values are then written with layerz_patch { branch_id }). 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.

ParametersJSON Schema
NameRequiredDescriptionDefault
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.

TDQS

A4.6/5.0
Behavior5/5

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

Goes well beyond the annotations: it discloses that `priority` is rejected on the default branch, that an explicit `actuals_through` locks the cutover (`actuals_through_locked`), that this persists exactly one labelled version, that it returns `{ branch, created }`, and that it is hidden from read-only keys. These are real behavioral facts an agent needs that no annotation or schema field carries.

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-loads the create/update dichotomy and the two modes, then layers in constraints. Dense but mostly every sentence earns its place; the parenthetical about `layerz_patch` and the read-only-key note are informative rather than filler, though the passage is fairly packed.

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?

No output schema exists, yet the description states the return shape (`{ branch, created }`), covers the nested `patch` object behavior, auth scoping (read-only keys), and the default-branch constraint. Nothing material for correct invocation is missing.

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?

Schema coverage is 75% (only `actuals_through`, `summary`, `model_id`, and `dataset_id` are documented; `patch.file_name`/`source_hint`/`priority` are not). The description compensates by enumerating the patchable metadata fields and explaining the pinning/reset semantics of `actuals_through`, adding meaning beyond the schema.

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?

States a specific verb+resource ('Creates or updates a branch') and immediately splits the two distinct code paths (with vs. without `dataset_id`). The dual create/update semantics and the metadata-patch scope are clear enough that an agent can distinguish it from `layerz_import_branch` or `layerz_patch` without opening the schema.

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?

Explicitly routes the agent: values are written with `layerz_patch { branch_id }`, so the agent knows this tool does not write rows. It also states the `priority` rejection on the default branch as a precondition. It stops short of explicitly comparing against siblings like import_branch/delete_branch, so no full when-not coverage.

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

layerz_validate_modelValidate modelA
Read-only
Inspect

Runs the core model validator (structural / formula / timeline checks) without writing and returns { ok, error_count, warning_count, errors[], warnings[] }; each issue carries a code (e.g. UNKNOWN_UID, CIRCULAR_DEPENDENCY, INVALID_ROLE_CHILD, TIMELINE_MISMATCH), a message and item_uids. The write path auto-repairs some of these issues and enforces a few invariants this audit skips, so ok: true is a sanity signal rather than a write guarantee.

ParametersJSON Schema
NameRequiredDescriptionDefault
model_idNoTarget model UUID. Required for user-scoped API keys; validated against the bound model for model-scoped keys.

TDQS

A4.2/5.0
Behavior5/5

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

Annotations cover the read-only profile, but the description adds substantial context beyond them: it enumerates the check categories, the concrete issue codes, and the crucial caveat that the write path auto-repairs issues and enforces invariants this audit skips. This tells the agent exactly what a clean result does and does not guarantee.

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 action and scope, then the return shape, then the caveat. Dense but each clause carries information; the return-shape detail is justified because no output schema exists. Slightly long but no wasted sentences.

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?

With no output schema, the description fully covers the return contract (ok, counts, issue arrays, code/message/item_uids) and closes the semantic gap between validation success and write success. An agent has everything needed to call and interpret it.

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

Parameters3/5

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

Schema coverage is 100% and the single model_id parameter is richly documented in the schema (user-scoped vs model-scoped key behavior). The description adds no parameter-level detail, so the baseline 3 applies.

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?

Specific verb+resource ('core model validator') scoped precisely to 'structural / formula / timeline checks' and explicitly contrasted with the write path. An agent can distinguish this audit from siblings like layerz_get_model or layerz_diff without opening a schema.

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

Usage Guidelines3/5

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

Usage is implied rather than stated: 'without writing' and the caveat that 'ok: true is a sanity signal rather than a write guarantee' suggest pre-write checking, but there is no explicit when-to-use or when-not-to-use versus siblings. No alternatives are named.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updates
    • Changedlayerz_manage_integration2 fields changed
      • changedInput schema / properties / config / properties / field_map / description
        Previous value: -"Tabular sources: source column → canonical field (txn_date, amount, category, description, account_number, period). A value is a column name, a 0-based index, or an array of columns joined with \" / \" as a composite key (category: [\"Sens\", \"Catégorie\"] routes \"Charge / Hébergement\" and \"Produit / Hébergement\" separately). `amount` and `txn_date` are single-column (`measures` covers several value columns). A change re-fetches and re-stages; rejected on a csv/fec file source, whose columns are fixed at import."New value: +"Tabular sources: source column → canonical field (txn_date, amount, category, description, account_number, period). A value is a column name, a 0-based index, or an array of columns joined with \" / \" as a composite key (category: [\"Sens\", \"Catégorie\"] routes \"Charge / Hébergement\" and \"Produit / Hébergement\" separately). `amount` and `txn_date` are single-column (`measures` covers several value columns). A change re-fetches and re-stages. API connectors (Qonto, Pennylane, Stripe): a payload field name per description / category / account_number, taken from `source_fields` in layerz_list_integrations (e.g. Pennylane ledger `{ description: \"entryLabel\", category: \"accountLabel\" }`); a change re-derives the staged rows from their payloads and replays, no provider fetch. Rejected on a csv/fec file source, whose columns are fixed at import."
      • changedInput schema / properties / config / properties / label_field / description
        Previous value: -"Qonto: field the rows are grouped by (counterparty | label | category)."New value: +"Deprecated Qonto alias of `classify_by` + `field_map.description` (counterparty | label | category); still accepted, folded on the next projection."
    • Changedlayerz_patch1 field changed
      • changedInput schema / properties / ops / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "aggregation": {
        -        "enum": [
        -          "sum",
        -          "average",
        -          "stock"
        -        ],
        -        "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."
        -      },
        -      "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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_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.",
        -        "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"
        -      },
        -      "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). 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"
        -        ],
        -        "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"
        -      },
        -      "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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_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.",
        -        "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"
        -      },
        -      "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). 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"
        -            ],
        -            "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"
        -          },
        -          "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -            "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_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.",
        -            "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"
        -          },
        -          "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). 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"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "aggregation": {
        +        "enum": [
        +          "sum",
        +          "average",
        +          "stock"
        +        ],
        +        "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."
        +      },
        +      "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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.",
        +        "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"
        +      },
        +      "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). 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"
        +        ],
        +        "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"
        +      },
        +      "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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.",
        +        "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"
        +      },
        +      "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). 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"
        +            ],
        +            "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"
        +          },
        +          "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +            "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.",
        +            "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"
        +          },
        +          "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). 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"
        +  }
        +]
  2. 2 tool updates
    • Changedlayerz_external_ref1 field changed
      • addedInput schema / properties / links
        Added value: +{
        +  "description": "`link`: up to 200 links written as one batch, in place of the flat fields.",
        +  "items": {
        +    "properties": {
        +      "name": {
        +        "description": "`link`: display name (default: the source item's name).",
        +        "maxLength": 200,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "parent": {
        +        "description": "`link` (create): parent container uid (section / formula / balance / dashboard).",
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "source_model_id": {
        +        "description": "`link`: the model read from.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "source_uid": {
        +        "description": "`link`: uid of the source item in that model.",
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "timeline_ref": {
        +        "description": "`link`: grain of the linked line (default: the source's grain when active here, else the finest active grain).",
        +        "enum": [
        +          "constant",
        +          "monthly",
        +          "quarterly",
        +          "yearly"
        +        ],
        +        "type": "string"
        +      },
        +      "uid": {
        +        "description": "`link`: existing non-list assumption to retarget.",
        +        "maxLength": 100,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source_model_id",
        +      "source_uid"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 200,
        +  "minItems": 1,
        +  "type": "array"
        +}
    • Changedlayerz_manage_mapping8 fields changed
      • addedInput schema / properties / mapping_ids
        Added value: +{
        +  "description": "`delete`: up to 500 rule ids removed as one batch.",
        +  "items": {
        +    "format": "uuid",
        +    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +    "type": "string"
        +  },
        +  "maxItems": 500,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / properties / pattern / description
        Previous value: -"`set`: primary key glob (`*` anywhere) or exact value."New value: +"Primary key glob (`*` anywhere) or exact value."
      • addedInput schema / properties / pattern / maxLength
        Added value: +200
      • addedInput schema / properties / rules
        Added value: +{
        +  "description": "`set`: up to 500 rules written as one batch, in place of the flat fields.",
        +  "items": {
        +    "properties": {
        +      "pattern": {
        +        "description": "Primary key glob (`*` anywhere) or exact value.",
        +        "maxLength": 200,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "secondary_pattern": {
        +        "description": "Secondary key glob tested against the source's `dimension_by` field (default `*` = any).",
        +        "maxLength": 200,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "sign": {
        +        "description": "Sign convention applied to the matched amount (default natural).",
        +        "enum": [
        +          "natural",
        +          "negate",
        +          "absolute"
        +        ],
        +        "type": "string"
        +      },
        +      "source_id": {
        +        "description": "Scopes the rule to one data source of the model (id from layerz_list_integrations). Omitted = model-wide.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "target": {
        +        "description": "Target item name or uid; `uid::entryUid` pins one list entry; `__ignore__` routes nowhere on purpose.",
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "pattern",
        +      "target"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 500,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / properties / secondary_pattern / description
        Previous value: -"`set`: secondary key glob tested against the source's `dimension_by` field (default `*` = any)."New value: +"Secondary key glob tested against the source's `dimension_by` field (default `*` = any)."
      • changedInput schema / properties / sign / description
        Previous value: -"`set`: sign convention applied to the matched amount (default natural)."New value: +"Sign convention applied to the matched amount (default natural)."
      • changedInput schema / properties / source_id / description
        Previous value: -"`set`: scopes the rule to one data source of the model (id from layerz_list_integrations). Omitted = model-wide."New value: +"Scopes the rule to one data source of the model (id from layerz_list_integrations). Omitted = model-wide."
      • changedInput schema / properties / target / description
        Previous value: -"`set`: target item name or uid; `uid::entryUid` pins one list entry; `__ignore__` routes nowhere on purpose."New value: +"Target item name or uid; `uid::entryUid` pins one list entry; `__ignore__` routes nowhere on purpose."
  3. 1 tool update
    • Changedlayerz_read2 fields changed
      • changedInput schema / properties / branch_id / description
        Previous value: -"Branch whose `[base, branch]` checkout the values are computed under, instead of the stacked-all view (base-vs-overlay audit); `default` = the base plan alone. Requires with_values."New value: +"Branch whose `[base, branch]` checkout the values `v` and the check report `health` are computed under, instead of the stacked-all view (base-vs-overlay audit); `default` = the base plan alone. An unknown id is rejected. Requires with_values or health."
      • changedInput schema / properties / health / description
        Previous value: -"Also returns the `health` block: non-blocking check violations (lines flagged `check`), evaluated at the finest active grain. `with_values: true` already includes `health` when the model has checks; this flag returns `health` without the full value series."New value: +"Also returns the `health` block: non-blocking check violations (lines flagged `check`), evaluated at the finest active grain under a branch checkout rather than the stacked view: the `branch_id` requested, else on a multi-branch model the branch the model opens on (`health.branch_id`) with every branch's verdict under `health.by_branch`. `with_values: true` already includes `health` when the model has checks; this flag returns `health` without the full value series."
  4. 44 tool updates
    • Changedlayerz_build_from_blueprint6 fields changed
      • changedInput schema / properties / blueprint / description
        Previous value: -"Strict Blueprint object. Shape: { project?: string, timelines?: { monthly?: {start,end}, yearly?: {start,end}, quarterly?: {start,end} }, lists?: [{ display_name, items: [{label, mapped_to?: Record<targetListDisplayName, sourceLabels[]>}] }], sections: [{ name: \"P&L\", items: [{ role: \"assumption\" | \"formula\" | \"callup\" | \"balance\" | \"chart\" | \"dashboard\" | \"kpi\" | \"mini_table\", name, timeline_ref?, value?, values?, formula?, item_style?, opening_balance?, liste_ref?, timeline_values?: Record<elementLabel, (number|null)[]>, children?: [{name}], … }] }], dashboards?: [{ name, items: [{role: \"chart\" | \"kpi\" | \"mini_table\", …}] }] }. At least one section is required. Items reference each other by display_name (formula inputs, callup source, chart series). Stock-flow pattern: declare a `balance` with `opening_balance` and put `callup` items inside its `items` referencing the source flows by name; outflows must be formulas that return negative values; break self-referencing cycles with the lag suffix `_M-1` / `_Q-1` / `_Y-1` on the balance name. Roll-forwards & recursion use the lag suffix `<name>_M-N` / `_Q-N` / `_Y-N` (self-referencing lag is allowed, e.g. `Tariff = Tariff_Y-1 * (1 + Inflation)`); for BOP/EOP prefer a `balance` with `opening_balance` and `children` for the period flows. Full roll-forward cookbook (debt, DSRA, rolling min DSCR, balance-list) in docs/mdk-format.md. List mode (per-element series via the lists registry): declare named lists in `lists: [{display_name:\"Functions\", items:[{label:\"Engineering\"},{label:\"Sales\"},{label:\"G&A\"}]}]`, then bind a consumer item via `liste_ref:\"Functions\"` and provide `timeline_values: {Engineering:[1200000,1500000], Sales:[800000,950000], \"G&A\":[400000,420000]}` keyed by **element label** (resolved to UIDs at compile time). Works for `assumption`, `formula`, and `balance`. Two-dimension breakdowns compose with `mapped_to` on the list element: `lists:[{display_name:\"Products\", items:[{label:\"Pro\"},{label:\"Enterprise\"}]}, {display_name:\"Channels\", items:[{label:\"Direct\", mapped_to:{Products:[\"Pro\",\"Enterprise\"]}}, {label:\"Partner\"}, {label:\"Self-serve\"}]}]` says channel Direct rolls up products Pro and Enterprise, enabling Revenue × Products × Channels cross-aggregation. Balance-list rule: a `balance` with `liste_ref` requires every list-typed child to share the same `liste_ref`; scalar children broadcast. Set `dry_run: true` to validate without mutating; errors come back with a path you can fix. Full schema: src/core/blueprint-schema.ts."New value: +"Strict Blueprint object: { project?, timelines?: { monthly? | quarterly? | yearly?: { start, end } }, lists?: [{ display_name, items: [{ label, mapped_to?: Record<listName, labels[]> }] }], sections: [{ name, items: [{ role, name, timeline_ref?, value?, values?, formula?, item_style?, opening_balance?, liste_ref?, timeline_values?: Record<elementLabel, (number|null)[]>, children?, … }] }], dashboards?: [{ name, items: [{ role: chart | kpi | mini_table, … }] }] }. At least one section is required. Items reference each other by name (formula inputs, callup source, chart series); a callup omits `name` and inherits its source's. A list-mode item binds a declared list through `liste_ref` and carries `timeline_values` keyed by element label; a `balance` with `liste_ref` requires every list-typed child to share it. Accepted as a JSON object or a JSON-encoded string."
      • changedInput schema / properties / dry_run / description
        Previous value: -"Validate the blueprint and report errors without writing anything."New value: +"Validates the blueprint and reports errors without writing."
      • changedInput schema / properties / mode / description
        Previous value: -"'merge' (default): add to the existing model, reusing items by display_name; a re-declared item keeps every presentation/annotation field the blueprint omits (style, format, note, check, placement). 'replace': rebuild the WHOLE model (structure, timelines, values, branches) from the blueprint — only the style colours, custom formats, locale, glyph, subtitle and FINANCE.md are kept."New value: +"'merge' (default): adds to the existing model, reusing items by name. 'replace': rebuilds the whole model from the blueprint."
      • 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."
      • 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 / properties / template_id / description
        Previous value: -"Apply a stored template as a module instead of an inline blueprint (mutually exclusive with `blueprint`). Discover ids via layerz_list_templates."New value: +"Stored template to apply as a module (mutually exclusive with `blueprint`)."
    • Changedlayerz_create_upload_url1 field changed
      • changedInput schema / properties / content_type / description
        Previous value: -"MIME type, e.g. \"text/csv\" or the xlsx spreadsheet content type."New value: +"MIME type, e.g. \"text/csv\" or the xlsx content type."
    • Changedlayerz_delete_branch2 fields changed
      • 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."
      • 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\"."
    • Removedlayerz_delete_integration
    • Removedlayerz_delete_mapping
    • Changedlayerz_dependencies1 field changed
      • 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."
    • Changedlayerz_diff7 fields changed
      • changedInput schema / properties / from / description
        Previous value: -"Older endpoint. Exactly one of revision_id / version_number / id."New value: +"Older endpoint: exactly one of revision_id / version_number / id."
      • changedInput schema / properties / from / properties / id / description
        Previous value: -"Raw model_versions row UUID (rare)."New value: +"Raw model_versions row UUID."
      • changedInput schema / properties / from / properties / revision_id / description
        Previous value: -"Content fingerprint (sha256:hex). Preferred — stable across DB renames."New value: +"Content fingerprint (sha256:hex), stable across DB renames."
      • 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."
      • changedInput schema / properties / to / description
        Previous value: -"Newer endpoint. Omit (or set to null) to diff against the current live model."New value: +"Newer endpoint; omitted = the current live model."
      • changedInput schema / properties / to / properties / id / description
        Previous value: -"Raw model_versions row UUID (rare)."New value: +"Raw model_versions row UUID."
      • changedInput schema / properties / to / properties / revision_id / description
        Previous value: -"Content fingerprint (sha256:hex). Preferred — stable across DB renames."New value: +"Content fingerprint (sha256:hex), stable across DB renames."
    • Changedlayerz_export2 fields changed
      • changedInput schema / properties / branch_id / description
        Previous value: -"Branch to export for the statements/single-value widgets. Defaults to the base branch. Dashboards keep every branch regardless. Discover ids via layerz_list_branches."New value: +"Branch the statements and single-value widgets follow (default: the base branch). Dashboards keep every branch."
      • 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."
    • Changedlayerz_external_ref11 fields changed
      • 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."
      • changedInput schema / properties / name / description
        Previous value: -"`link` only: display name (defaults to the source item's name)."New value: +"`link`: display name (default: the source item's name)."
      • changedInput schema / properties / op / description
        Previous value: -"link (create/retarget a ref) | refresh (re-sync snapshot values)."New value: +"link | refresh | unlink."
      • changedInput schema / properties / op / enum
        Previous value: -[
        -  "link",
        -  "refresh"
        -]New value: +[
        +  "link",
        +  "refresh",
        +  "unlink"
        +]
      • changedInput schema / properties / parent / description
        Previous value: -"`link` create only: parent container uid (section/formula/balance/dashboard)."New value: +"`link` (create): parent container uid (section / formula / balance / dashboard)."
      • changedInput schema / properties / source_model_id / description
        Previous value: -"`link` only: the model to read from (id from layerz_list_models)."New value: +"`link`: the model read from."
      • changedInput schema / properties / source_uid / description
        Previous value: -"`link` only: uid of the source item in that model."New value: +"`link`: uid of the source item in that model."
      • 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 / properties / timeline_ref / description
        Previous value: -"`link` only: grain of the linked line (default: the source's grain when active here, else the finest active grain)."New value: +"`link`: grain of the linked line (default: the source's grain when active here, else the finest active grain)."
      • changedInput schema / properties / uid / description
        Previous value: -"`link` only: retarget this existing non-list assumption instead of creating one."New value: +"`link`: existing non-list assumption to retarget. `unlink`: the linked line to detach."
      • changedInput schema / properties / uids / description
        Previous value: -"`refresh` only: restrict to these linked items (default: all)."New value: +"`refresh`: restricts the refresh to these linked items (default: all)."
    • Removedlayerz_external_ref_status
    • Addedlayerz_get_conventions
    • Removedlayerz_get_custom_instructions
    • Removedlayerz_get_finance_md
    • Changedlayerz_get_model1 field changed
      • 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."
    • Removedlayerz_get_template
    • Changedlayerz_history4 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max number of versions to return (default 100, clamped to plan retention)."New value: +"Max versions returned (default 100; with `uid`, max versions scanned, default 50)."
      • 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."
      • changedInput schema / properties / since / description
        Previous value: -"ISO timestamp lower bound — only versions created at or after this time."New value: +"ISO timestamp lower bound on the version list (ignored with `uid`)."
      • addedInput schema / properties / uid
        Added value: +{
        +  "description": "Item UID: returns that item's change events instead of the version list.",
        +  "maxLength": 64,
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Removedlayerz_history_for_item
    • Changedlayerz_import_branch3 fields changed
      • 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."
      • changedInput schema / properties / structure_override / properties / header_row_index / description
        Previous value: -"0-based header row. Omitted: re-detected for the requested `layout` (a columnar override never inherits the wide-layout period-row guess); the row used is reported back (`file_structure` on layerz_import_branch, `suggested_structure` on layerz_parse_file)."New value: +"0-based header row. Omitted: re-detected for the requested `layout` (a columnar override is re-detected rather than inheriting the wide-layout period-row guess); the row used is reported back (`file_structure` on layerz_import_branch, `suggested_structure` on layerz_parse_file)."
      • 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\"."
    • Removedlayerz_import_mapping_template
    • Removedlayerz_list_branches
    • Changedlayerz_list_integrations2 fields changed
      • addedInput schema / properties / include_external_refs
        Added value: +{
        +  "description": "Also return the external references (links to other models) with their staleness.",
        +  "type": "boolean"
        +}
      • 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."
    • Changedlayerz_list_mappings3 fields changed
      • changedInput schema / properties / include_coverage / description
        Previous value: -"Also compute, per rule, `match_count` (staged rows it captures) and a `coverage` block (auto-created count + top unrouted keys). Off by default — it classifies every source, so it is a heavier read."New value: +"Also compute `match_count` per rule and a `coverage` block (classifies every source: heavier read)."
      • changedInput schema / properties / include_user_mappings / description
        Previous value: -"Also surface your account-wide (model-independent) user catalogs in `sets`/`mappings` for discovery. Default false: only what this model actually classifies with (system + this-model rules)."New value: +"Also list the account-wide user catalogs in `sets` / `mappings` (default: only what the model classifies with)."
      • 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."
    • Changedlayerz_list_models2 fields changed
      • changedInput schema / properties / q / description
        Previous value: -"Optional name search filter. Substring, case-insensitive (e.g. \"swoop\" matches \"SWOOP - BP 2026\"). Use \"*\" as a wildcard; \"%\", \"_\" and \"&\" are literal."New value: +"Name filter: case-insensitive substring (\"swoop\" matches \"SWOOP - BP 2026\"); `*` is a wildcard, `%`, `_` and `&` are literal."
      • changedInput schema / properties / writable / description
        Previous value: -"When true, returns only models the caller can edit (owner or editor). Omit to return all accessible models."New value: +"When true, only models the caller can edit (owner or editor)."
    • Removedlayerz_list_shares
    • Changedlayerz_list_templates2 fields changed
      • changedInput schema / properties / scope / description
        Previous value: -"Filter by scope: \"system\" (curated) or \"user\" (your own)."New value: +"Scope filter: \"system\" (curated) or \"user\" (own templates)."
      • addedInput schema / properties / template_id
        Added value: +{
        +  "description": "One template in full (blueprint + usage guide) instead of the list.",
        +  "format": "uuid",
        +  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +  "type": "string"
        +}
    • Changedlayerz_list_transactions5 fields changed
      • changedInput schema / properties / connection_id / description
        Previous value: -"Connection id from layerz_list_integrations."New value: +"Source id as returned by layerz_list_integrations."
      • changedInput schema / properties / format / description
        Previous value: -"Default json (annotated rows inline). `csv`: export every staged row of the source as a CSV file and return a signed `download_url` (same file as the web Sources panel download)."New value: +"json (default): annotated rows inline. csv: a signed `download_url` of every staged row as a CSV file."
      • 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."
      • changedInput schema / properties / period / description
        Previous value: -"Keep only this YYYY-MM period."New value: +"Keeps only this YYYY-MM period."
      • changedInput schema / properties / q / description
        Previous value: -"Keep rows whose description/category contains this text."New value: +"Keeps rows whose description/category contains this text."
    • Changedlayerz_manage_integration22 fields changed
      • changedInput schema / properties / branch_ids / description
        Previous value: -"`rebind` only: the existing branches this connector should feed (e.g. [\"default\"])."New value: +"`rebind` only: the existing branches the source feeds afterwards (e.g. [\"default\"])."
      • changedInput schema / properties / config / properties / airtable / description
        Previous value: -"Airtable only: base/table (and optional view) to pull records from."New value: +"Airtable: base / table (and optional view) the records come from."
      • changedInput schema / properties / config / properties / classify_by / description
        Previous value: -"Which staged field the rules key on: account_number | description (label) | category. Re-projects from the staged rows."New value: +"Staged field the mapping rules key on: account_number | description (label) | category. Re-projects from the staged rows."
      • changedInput schema / properties / config / properties / field_map / description
        Previous value: -"Tabular sources: source column → canonical field (txn_date, amount, category, description, account_number, period). A value is a column name, a 0-based index, or an ARRAY of columns (composite key, cells joined with \" / \" — e.g. category: [\"Sens\",\"Catégorie\"] routes \"Charge / Hébergement\" and \"Produit / Hébergement\" separately). `amount` and `txn_date` are single-column (a list is rejected — use `measures` for several value columns). Changing it re-fetches + re-stages (tabular sources only — rejected on a csv/fec file source, whose columns are fixed at import: re-import the file instead)."New value: +"Tabular sources: source column → canonical field (txn_date, amount, category, description, account_number, period). A value is a column name, a 0-based index, or an array of columns joined with \" / \" as a composite key (category: [\"Sens\", \"Catégorie\"] routes \"Charge / Hébergement\" and \"Produit / Hébergement\" separately). `amount` and `txn_date` are single-column (`measures` covers several value columns). A change re-fetches and re-stages; rejected on a csv/fec file source, whose columns are fixed at import."
      • changedInput schema / properties / config / properties / import_level / description
        Previous value: -"Pennylane only: which resource to read — trial_balance (per-account monthly balances, default; account source), ledger (individual ledger entry lines keyed by PCG account; account source), or transactions (bank transactions keyed by label; label source). Changing it RE-FETCHES from Pennylane and re-stages (external ids differ per level), unlike the other config fields which only re-project."New value: +"Pennylane: resource read — trial_balance (per-account monthly balances, default), ledger (ledger entry lines keyed by PCG account) or transactions (bank transactions keyed by label). A change re-fetches and re-stages (external ids differ per level)."
      • changedInput schema / properties / config / properties / label_field / description
        Previous value: -"Qonto field to group by: counterparty | label | category."New value: +"Qonto: field the rows are grouped by (counterparty | label | category)."
      • changedInput schema / properties / config / properties / measures / description
        Previous value: -"Tabular sources: N measures per connection for object tables (one row = one object, measures in columns). Each measure stages one row per source row — amount from its column, or 1 when `count: true` — classified under its `key`, so ordinary mapping rules route each measure to its own item (e.g. [{column:\"Jours\"},{column:\"Participants\"},{count:true,key:\"Séjours réalisés\"}] feeds three items from ONE connection, no helper columns in the source). Mutually exclusive with field_map.amount; `classify_by` must be \"category\" or unset; `field_map` still carries txn_date/period. Changing it re-fetches + re-stages (tabular sources only)."New value: +"Tabular sources: several measures per connection for object tables (one row = one object, measures in columns). Each measure stages one row per source row (its column value, or 1 with `count: true`) classified under its `key`, so ordinary mapping rules route each measure to its own item. Mutually exclusive with `field_map.amount`; `classify_by` is \"category\" or unset. A change re-fetches and re-stages (tabular sources only)."
      • changedInput schema / properties / config / properties / measures / items / properties / column / description
        Previous value: -"Value column (header name or 0-based index). Omit for count: true."New value: +"Value column (header name or 0-based index); absent with `count: true`."
      • changedInput schema / properties / config / properties / measures / items / properties / count / description
        Previous value: -"Read the literal 1 per source row (native row counter)."New value: +"Stages the literal 1 per source row (row counter)."
      • changedInput schema / properties / config / properties / measures / items / properties / key / description
        Previous value: -"Classification key the mapping rules route on. Defaults to the column header; required on a count measure."New value: +"Classification key the mapping rules route on; defaults to the column header, required on a count measure."
      • changedInput schema / properties / config / properties / metabase / description
        Previous value: -"Metabase only: the saved question whose results feed the source."New value: +"Metabase: the saved question whose results feed the source."
      • changedInput schema / properties / config / properties / sign_rule / description
        Previous value: -"Tabular sources: negate `amount` when `field` equals one of `negate_values` (e.g. { field: \"Sens\", negate_values: [\"Charge\"] }). Changing it re-fetches + re-stages (tabular sources only)."New value: +"Tabular sources: negates `amount` when `field` equals one of `negate_values` ({ field: \"Sens\", negate_values: [\"Charge\"] }). A change re-fetches and re-stages (tabular sources only)."
      • changedInput schema / properties / config / properties / window / description
        Previous value: -"Confirm the source's authoritative window (months YYYY-MM, inclusive). It BOUNDS the projection: staged rows whose period falls outside [start, end] produce no input in the branch (skipped as `outside confirmed window` — e.g. the in-progress month past the last closed one), inside it every line the source owns (an item a rule targets) with no transaction is forced to 0, and the window `end` becomes the real/forecast cutover (`actuals_through` — the branch keeps the LATEST window end across its sources; any rewrite is reported in `cutover_changes` + `warnings`). Tightening the window then `update`/`sync` also purges previously projected out-of-window inputs (the re-projection replaces this source's whole contribution). A `sync`/`dry_run` returns `proposed_window` to confirm here. Requires full mapping in-window (unmapped keys are surfaced but do not block)."New value: +"The source's authoritative window (months YYYY-MM, inclusive). Staged rows outside [start, end] produce no input (skipped as `outside confirmed window`); inside it, every line the source owns with no transaction reads an explicit 0, and `end` becomes the branch's real/forecast cutover (`actuals_through`, latest window end across its sources; rewrites are reported in `cutover_changes`). Tightening the window purges previously projected out-of-window inputs on the next projection. A `sync` returns `proposed_window` (the staged min/max month)."
      • addedInput schema / properties / confirm_purge
        Added value: +{
        +  "description": "`delete` only: confirms the purge after a `PURGE_CONFIRMATION_REQUIRED` refusal.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / connection_id / description
        Previous value: -"Connection id from layerz_list_integrations."New value: +"Source id as returned by layerz_list_integrations."
      • changedInput schema / properties / display_name / description
        Previous value: -"`update` only: new display label for the source (Sources panel + layerz_list_integrations). Pure metadata — no reprojection."New value: +"`update` only: new label of the source (metadata, no reprojection)."
      • changedInput schema / properties / dry_run / description
        Previous value: -"`sync` only: preview the impact without persisting."New value: +"`sync` only: reports the impact without persisting."
      • 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."
      • changedInput schema / properties / op / description
        Previous value: -"Which mutation to run on the connector."New value: +"Operation to run on the source."
      • changedInput schema / properties / op / enum
        Previous value: -[
        -  "sync",
        -  "update",
        -  "rebind"
        -]New value: +[
        +  "sync",
        +  "update",
        +  "rebind",
        +  "delete"
        +]
      • 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 / properties / target_branch_id / description
        Previous value: -"`sync` only: existing branch id to feed for a still-unbound connection (e.g. `default`). Ignored once the connection is bound."New value: +"`sync` only: existing branch a still-unbound connection feeds (e.g. `default`). Ignored once bound."
    • Addedlayerz_manage_mapping
    • Addedlayerz_manage_version
    • Changedlayerz_match_items2 fields changed
      • changedInput schema / properties / labels / description
        Previous value: -"Free-text labels to resolve (e.g. row labels from an Excel sheet)."New value: +"Free-text labels to resolve."
      • 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."
    • Changedlayerz_parse_file3 fields changed
      • changedInput schema / properties / file_id / description
        Previous value: -"Upload identifier returned by layerz_create_upload_url (format: 'f_' + 16 hex chars)."New value: +"Upload id as returned by layerz_create_upload_url ('f_' + 16 hex chars)."
      • changedInput schema / properties / sheet_name / description
        Previous value: -"Target sheet name for multi-sheet workbooks. Omit to get sheet summaries."New value: +"Sheet of a multi-sheet workbook. Omitted: sheet summaries only."
      • changedInput schema / properties / structure_override / properties / header_row_index / description
        Previous value: -"0-based header row. Omitted: re-detected for the requested `layout` (a columnar override never inherits the wide-layout period-row guess); the row used is reported back (`file_structure` on layerz_import_branch, `suggested_structure` on layerz_parse_file)."New value: +"0-based header row. Omitted: re-detected for the requested `layout` (a columnar override is re-detected rather than inheriting the wide-layout period-row guess); the row used is reported back (`file_structure` on layerz_import_branch, `suggested_structure` on layerz_parse_file)."
    • Changedlayerz_patch6 fields changed
      • addedInput schema / properties / branch_id
        Added value: +{
        +  "description": "Branch that receives the value writes of this batch (`update` / `replace` `value`, `values`, `timeline_values` on assumptions): only the cells that differ from the base are stored as that branch's overlay, the same record a value edit makes in the web editor with the branch checked out; no data source is created. Absent or `default`: the base plan. Structural ops and non-value fields apply to the model as a whole; a `create` carrying values under a branch is rejected. An unknown id is rejected.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / compute_branch / description
        Previous value: -"Return the `compute` values under a single branch's `[base, branch]` checkout instead of the stacked-all view (mirror of `layerz_read` `branch_id`). Pass `default` to audit the base plan alone — e.g. verify a base correction without a live import layer polluting the result. Requires `compute`. Does not change where the write lands (always the base)."New value: +"Branch whose `[base, branch]` checkout the `compute` values are returned under, instead of the stacked-all view (mirror of `layerz_read` `branch_id`); `default` = the base plan alone. Defaults to `branch_id` when that is set. Requires `compute`."
      • changedInput schema / properties / dry_run / description
        Previous value: -"Validate and compute the batch without persisting it"New value: +"Validates and computes the batch without persisting it."
      • 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."
      • changedInput schema / properties / ops / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "aggregation": {
        -        "enum": [
        -          "sum",
        -          "average",
        -          "stock"
        -        ],
        -        "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": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        -      },
        -      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "maxLength": 50,
        -        "type": "string"
        -      },
        -      "formula": {
        -        "maxLength": 2000,
        -        "type": "string"
        -      },
        -      "inputs": {
        -        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "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"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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 never 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"
        -        ],
        -        "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": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -      },
        -      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "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"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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 never 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"
        -            ],
        -            "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": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -          },
        -          "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -            "maxLength": 50,
        -            "type": "string"
        -          },
        -          "formula": {
        -            "maxLength": 2000,
        -            "type": "string"
        -          },
        -          "inputs": {
        -            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -            "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -            "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"
        -          },
        -          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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 never 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. Pass false to rebuild 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"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "aggregation": {
        +        "enum": [
        +          "sum",
        +          "average",
        +          "stock"
        +        ],
        +        "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."
        +      },
        +      "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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_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.",
        +        "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"
        +      },
        +      "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). 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"
        +        ],
        +        "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"
        +      },
        +      "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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_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.",
        +        "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"
        +      },
        +      "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). 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"
        +            ],
        +            "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"
        +          },
        +          "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +            "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_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.",
        +            "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"
        +          },
        +          "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). 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"
        +  }
        +]
      • 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\"."
    • Removedlayerz_pin_version
    • Changedlayerz_promote_template5 fields changed
      • changedInput schema / properties / description / description
        Previous value: -"Optional usage guide (FINANCE.md). Leaves the model’s own when omitted."New value: +"Usage guide (FINANCE.md). The model keeps its own when omitted."
      • 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."
      • changedInput schema / properties / name / description
        Previous value: -"Template title — renames the model in place when it differs."New value: +"Template title; renames the model in place when it differs."
      • changedInput schema / properties / scope / description
        Previous value: -"Template scope. `user` (default) = private, owner-only, Pro-gated. `system` = curated public catalog, admin-only."New value: +"`user` (default): private, owner-only, Pro-gated. `system`: curated public catalog, admin-only."
      • 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\"."
    • Changedlayerz_read3 fields changed
      • changedInput schema / properties / branch_id / description
        Previous value: -"Compute values under a single branch's `[base, branch]` checkout instead of the stacked-all view — lets you audit base-vs-overlay (e.g. confirm the budget on the base, or what one branch changed). Pass `default` for the base plan alone. Requires with_values."New value: +"Branch whose `[base, branch]` checkout the values are computed under, instead of the stacked-all view (base-vs-overlay audit); `default` = the base plan alone. Requires with_values."
      • changedInput schema / properties / health / description
        Previous value: -"Also return the `health` block: non-blocking check violations (lines flagged `check`). Checks are evaluated at the finest active grain. `with_values: true` already includes `health` when the model has checks; set this to get `health` without the full value series."New value: +"Also returns the `health` block: non-blocking check violations (lines flagged `check`), evaluated at the finest active grain. `with_values: true` already includes `health` when the model has checks; this flag returns `health` without the full value series."
      • 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."
    • Removedlayerz_restore_version
    • Removedlayerz_revoke_share
    • Changedlayerz_set_custom_instructions1 field changed
      • changedInput schema / properties / content / description
        Previous value: -"Account-wide custom instructions (plain Markdown/text). Max 3000 chars. Empty string clears them."New value: +"Account-wide custom instructions, max 3000 chars. Empty string clears them."
    • Changedlayerz_set_finance_md4 fields changed
      • changedInput schema / properties / content / description
        Previous value: -"Full FINANCE.md Markdown (YAML front-matter + body). Max 5,000 chars — keep conventions in prose."New value: +"Full FINANCE.md Markdown (YAML front matter + body), max 5,000 chars."
      • 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."
      • changedInput schema / properties / source / description
        Previous value: -"Provenance: 'imported' when syncing from a project-root FINANCE.md, 'user' when editing in place. Defaults to 'user'."New value: +"Provenance: 'imported' (synced from a project-root FINANCE.md) or 'user' (default)."
      • 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\"."
    • Removedlayerz_set_mapping
    • Changedlayerz_share_model6 fields changed
      • changedInput schema / properties / email / description
        Previous value: -"The email address to invite."New value: +"`invite`: the email address to invite."
      • 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 / op
        Added value: +{
        +  "default": "invite",
        +  "description": "invite (default) | revoke.",
        +  "enum": [
        +    "invite",
        +    "revoke"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / principal_id
        Added value: +{
        +  "description": "`revoke`: collaborator user id or pending-invite id from `sharing.members`.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / role / description
        Previous value: -"viewer (read-only) or editor (can edit). Defaults to viewer."New value: +"`invite`: viewer (read-only, default) or editor."
      • removedInput schema / required
        Removed value: -[
        -  "email"
        -]
    • Removedlayerz_unlink_external_ref
    • Changedlayerz_update_branch5 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"
        +]
    • Changedlayerz_validate_model1 field changed
      • 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."
  5. 4 tool updates
    • Changedlayerz_import_branch1 field changed
      • addedInput schema / properties / structure_override / properties / header_row_index / description
        Added value: +"0-based header row. Omitted: re-detected for the requested `layout` (a columnar override never inherits the wide-layout period-row guess); the row used is reported back (`file_structure` on layerz_import_branch, `suggested_structure` on layerz_parse_file)."
    • Changedlayerz_manage_integration3 fields changed
      • changedInput schema / properties / config / properties / field_map / description
        Previous value: -"Tabular sources: source column → canonical field (txn_date, amount, category, description, account_number, period). A value is a column name, a 0-based index, or an ARRAY of columns (composite key, cells joined with \" / \" — e.g. category: [\"Sens\",\"Catégorie\"] routes \"Charge / Hébergement\" and \"Produit / Hébergement\" separately). `amount` and `txn_date` are single-column (a list is rejected — use `measures` for several value columns). Changing it re-fetches + re-stages."New value: +"Tabular sources: source column → canonical field (txn_date, amount, category, description, account_number, period). A value is a column name, a 0-based index, or an ARRAY of columns (composite key, cells joined with \" / \" — e.g. category: [\"Sens\",\"Catégorie\"] routes \"Charge / Hébergement\" and \"Produit / Hébergement\" separately). `amount` and `txn_date` are single-column (a list is rejected — use `measures` for several value columns). Changing it re-fetches + re-stages (tabular sources only — rejected on a csv/fec file source, whose columns are fixed at import: re-import the file instead)."
      • changedInput schema / properties / config / properties / measures / description
        Previous value: -"Tabular sources: N measures per connection for object tables (one row = one object, measures in columns). Each measure stages one row per source row — amount from its column, or 1 when `count: true` — classified under its `key`, so ordinary mapping rules route each measure to its own item (e.g. [{column:\"Jours\"},{column:\"Participants\"},{count:true,key:\"Séjours réalisés\"}] feeds three items from ONE connection, no helper columns in the source). Mutually exclusive with field_map.amount; `classify_by` must be \"category\" or unset; `field_map` still carries txn_date/period. Changing it re-fetches + re-stages."New value: +"Tabular sources: N measures per connection for object tables (one row = one object, measures in columns). Each measure stages one row per source row — amount from its column, or 1 when `count: true` — classified under its `key`, so ordinary mapping rules route each measure to its own item (e.g. [{column:\"Jours\"},{column:\"Participants\"},{count:true,key:\"Séjours réalisés\"}] feeds three items from ONE connection, no helper columns in the source). Mutually exclusive with field_map.amount; `classify_by` must be \"category\" or unset; `field_map` still carries txn_date/period. Changing it re-fetches + re-stages (tabular sources only)."
      • changedInput schema / properties / config / properties / sign_rule / description
        Previous value: -"Tabular sources: negate `amount` when `field` equals one of `negate_values` (e.g. { field: \"Sens\", negate_values: [\"Charge\"] }). Changing it re-fetches + re-stages."New value: +"Tabular sources: negate `amount` when `field` equals one of `negate_values` (e.g. { field: \"Sens\", negate_values: [\"Charge\"] }). Changing it re-fetches + re-stages (tabular sources only)."
    • Changedlayerz_parse_file1 field changed
      • addedInput schema / properties / structure_override / properties / header_row_index / description
        Added value: +"0-based header row. Omitted: re-detected for the requested `layout` (a columnar override never inherits the wide-layout period-row guess); the row used is reported back (`file_structure` on layerz_import_branch, `suggested_structure` on layerz_parse_file)."
    • Changedlayerz_set_mapping3 fields changed
      • changedInput schema / properties / pattern / description
        Previous value: -"Wildcard-prefix or exact pattern, e.g. \"Apport*\"."New value: +"Primary key glob (`*` anywhere) or exact value, e.g. \"Apport*\"."
      • addedInput schema / properties / secondary_pattern
        Added value: +{
        +  "description": "Secondary key glob tested against the source's `dimension_by` field (default `*` = any). Omitted = single-key rule.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / source_id
        Added value: +{
        +  "description": "Scope the rule to ONE data source of this model (id from layerz_list_integrations). Omitted = model-wide.",
        +  "format": "uuid",
        +  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +  "type": "string"
        +}
  6. 2 tool updates
    • Changedlayerz_build_from_blueprint1 field changed
      • changedInput schema / properties / mode / description
        Previous value: -"'merge' (default): add to the existing model, reusing items by display_name. 'replace': wipe non-default sections first."New value: +"'merge' (default): add to the existing model, reusing items by display_name; a re-declared item keeps every presentation/annotation field the blueprint omits (style, format, note, check, placement). 'replace': rebuild the WHOLE model (structure, timelines, values, branches) from the blueprint — only the style colours, custom formats, locale, glyph, subtitle and FINANCE.md are kept."
    • Changedlayerz_patch1 field changed
      • changedInput schema / properties / ops / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "aggregation": {
        -        "enum": [
        -          "sum",
        -          "average",
        -          "stock"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "check": {
        -        "anyOf": [
        -          {
        -            "properties": {
        -              "tolerance": {
        -                "exclusiveMinimum": 0,
        -                "type": "number"
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        -      },
        -      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "maxLength": 50,
        -        "type": "string"
        -      },
        -      "formula": {
        -        "maxLength": 2000,
        -        "type": "string"
        -      },
        -      "inputs": {
        -        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "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"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "check": {
        -        "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -      },
        -      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "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"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -            ],
        -            "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"
        -          },
        -          "chart_type": {
        -            "enum": [
        -              "line",
        -              "bar",
        -              "area",
        -              "bridge"
        -            ],
        -            "type": "string"
        -          },
        -          "check": {
        -            "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -          },
        -          "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -            "maxLength": 50,
        -            "type": "string"
        -          },
        -          "formula": {
        -            "maxLength": 2000,
        -            "type": "string"
        -          },
        -          "inputs": {
        -            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -            "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -            "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"
        -          },
        -          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -          },
        -          "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_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"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "aggregation": {
        +        "enum": [
        +          "sum",
        +          "average",
        +          "stock"
        +        ],
        +        "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": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        +      },
        +      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "maxLength": 50,
        +        "type": "string"
        +      },
        +      "formula": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "inputs": {
        +        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "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"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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 never 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"
        +        ],
        +        "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": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +      },
        +      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "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"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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 never 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"
        +            ],
        +            "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": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +          },
        +          "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +            "maxLength": 50,
        +            "type": "string"
        +          },
        +          "formula": {
        +            "maxLength": 2000,
        +            "type": "string"
        +          },
        +          "inputs": {
        +            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +            "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +            "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"
        +          },
        +          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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 never 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. Pass false to rebuild 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"
        +  }
        +]
  7. 1 tool update
    • Changedlayerz_patch1 field changed
      • changedInput schema / properties / ops / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "aggregation": {
        -        "enum": [
        -          "sum",
        -          "average",
        -          "stock"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "check": {
        -        "anyOf": [
        -          {
        -            "properties": {
        -              "tolerance": {
        -                "exclusiveMinimum": 0,
        -                "type": "number"
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        -      },
        -      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "maxLength": 50,
        -        "type": "string"
        -      },
        -      "formula": {
        -        "maxLength": 2000,
        -        "type": "string"
        -      },
        -      "inputs": {
        -        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "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"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "check": {
        -        "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -      },
        -      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "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"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -            ],
        -            "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"
        -          },
        -          "chart_type": {
        -            "enum": [
        -              "line",
        -              "bar",
        -              "area",
        -              "bridge"
        -            ],
        -            "type": "string"
        -          },
        -          "check": {
        -            "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -          },
        -          "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -            "maxLength": 50,
        -            "type": "string"
        -          },
        -          "formula": {
        -            "maxLength": 2000,
        -            "type": "string"
        -          },
        -          "inputs": {
        -            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -            "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -            "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"
        -          },
        -          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -          },
        -          "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_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"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "aggregation": {
        +        "enum": [
        +          "sum",
        +          "average",
        +          "stock"
        +        ],
        +        "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"
        +      },
        +      "chart_type": {
        +        "enum": [
        +          "line",
        +          "bar",
        +          "area",
        +          "bridge"
        +        ],
        +        "type": "string"
        +      },
        +      "check": {
        +        "anyOf": [
        +          {
        +            "properties": {
        +              "tolerance": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        +      },
        +      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "maxLength": 50,
        +        "type": "string"
        +      },
        +      "formula": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "inputs": {
        +        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "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"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +      },
        +      "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"
        +        ],
        +        "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"
        +      },
        +      "chart_type": {
        +        "enum": [
        +          "line",
        +          "bar",
        +          "area",
        +          "bridge"
        +        ],
        +        "type": "string"
        +      },
        +      "check": {
        +        "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +      },
        +      "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "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"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +      },
        +      "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"
        +            ],
        +            "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"
        +          },
        +          "chart_type": {
        +            "enum": [
        +              "line",
        +              "bar",
        +              "area",
        +              "bridge"
        +            ],
        +            "type": "string"
        +          },
        +          "check": {
        +            "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +          },
        +          "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; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +            "maxLength": 50,
        +            "type": "string"
        +          },
        +          "formula": {
        +            "maxLength": 2000,
        +            "type": "string"
        +          },
        +          "inputs": {
        +            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +            "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +            "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"
        +          },
        +          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +          },
        +          "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_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"
        +  }
        +]
  8. 1 tool update
    • Changedlayerz_patch1 field changed
      • changedInput schema / properties / ops / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "aggregation": {
        -        "enum": [
        -          "sum",
        -          "average",
        -          "stock"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "check": {
        -        "anyOf": [
        -          {
        -            "properties": {
        -              "tolerance": {
        -                "exclusiveMinimum": 0,
        -                "type": "number"
        -              }
        -            },
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        -      },
        -      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "maxLength": 50,
        -        "type": "string"
        -      },
        -      "formula": {
        -        "maxLength": 2000,
        -        "type": "string"
        -      },
        -      "inputs": {
        -        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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_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. Pass null to clear (back to fit-to-data)."
        -      },
        -      "role": {
        -        "description": "Change the item role. Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "enum": [
        -          "assumption",
        -          "formula",
        -          "callup",
        -          "balance",
        -          "section",
        -          "chart",
        -          "dashboard",
        -          "kpi",
        -          "mini_table"
        -        ],
        -        "type": "string"
        -      },
        -      "row_break": {
        -        "description": "dashboard-child line break: start this widget on a fresh grid row",
        -        "type": "boolean"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "check": {
        -        "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -      },
        -      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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. Use 'total' to chart a list total 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_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. Pass null to clear (back to fit-to-data)."
        -      },
        -      "role": {
        -        "description": "Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "enum": [
        -          "assumption",
        -          "formula",
        -          "callup",
        -          "balance",
        -          "section",
        -          "chart",
        -          "dashboard",
        -          "kpi",
        -          "mini_table"
        -        ],
        -        "type": "string"
        -      },
        -      "row_break": {
        -        "description": "dashboard-child line break: start this widget on a fresh grid row",
        -        "type": "boolean"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -            ],
        -            "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"
        -          },
        -          "chart_type": {
        -            "enum": [
        -              "line",
        -              "bar",
        -              "area",
        -              "bridge"
        -            ],
        -            "type": "string"
        -          },
        -          "check": {
        -            "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        -          },
        -          "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -            "maxLength": 50,
        -            "type": "string"
        -          },
        -          "formula": {
        -            "maxLength": 2000,
        -            "type": "string"
        -          },
        -          "inputs": {
        -            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -            "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. Use 'total' to chart a list total 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_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. Pass null to clear (back to fit-to-data)."
        -          },
        -          "role": {
        -            "description": "Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -            "enum": [
        -              "assumption",
        -              "formula",
        -              "callup",
        -              "balance",
        -              "section",
        -              "chart",
        -              "dashboard",
        -              "kpi",
        -              "mini_table"
        -            ],
        -            "type": "string"
        -          },
        -          "row_break": {
        -            "description": "dashboard-child line break: start this widget on a fresh grid row",
        -            "type": "boolean"
        -          },
        -          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -          },
        -          "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_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"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "aggregation": {
        +        "enum": [
        +          "sum",
        +          "average",
        +          "stock"
        +        ],
        +        "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"
        +      },
        +      "chart_type": {
        +        "enum": [
        +          "line",
        +          "bar",
        +          "area",
        +          "bridge"
        +        ],
        +        "type": "string"
        +      },
        +      "check": {
        +        "anyOf": [
        +          {
        +            "properties": {
        +              "tolerance": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        +      },
        +      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "maxLength": 50,
        +        "type": "string"
        +      },
        +      "formula": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "inputs": {
        +        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "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"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +      },
        +      "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"
        +        ],
        +        "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"
        +      },
        +      "chart_type": {
        +        "enum": [
        +          "line",
        +          "bar",
        +          "area",
        +          "bridge"
        +        ],
        +        "type": "string"
        +      },
        +      "check": {
        +        "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +      },
        +      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "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"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +      },
        +      "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"
        +            ],
        +            "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"
        +          },
        +          "chart_type": {
        +            "enum": [
        +              "line",
        +              "bar",
        +              "area",
        +              "bridge"
        +            ],
        +            "type": "string"
        +          },
        +          "check": {
        +            "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +          },
        +          "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +            "maxLength": 50,
        +            "type": "string"
        +          },
        +          "formula": {
        +            "maxLength": 2000,
        +            "type": "string"
        +          },
        +          "inputs": {
        +            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +            "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. Use 'total' to chart a list total 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_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. Pass null to clear (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 — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +            "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"
        +          },
        +          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +          },
        +          "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_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"
        +  }
        +]
  9. 2 tool updates
    • Changedlayerz_patch1 field changed
      • changedInput schema / properties / ops / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "aggregation": {
        -        "enum": [
        -          "sum",
        -          "average",
        -          "stock"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "maxLength": 50,
        -        "type": "string"
        -      },
        -      "formula": {
        -        "maxLength": 2000,
        -        "type": "string"
        -      },
        -      "inputs": {
        -        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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": "Business watchpoint. `assert` is a boolean expression where the reserved token `value` is this item's computed value (a leading comparator like \"== 0\" implies it). Values are evaluated rounded to 2 decimals, so \"== 0\" already absorbs sub-0.005 residuals (a balance netting to 1e-11 reads as 0 and passes); use a wider tolerance (\"ABS(value) < 1\") only to ignore a materially larger gap. Pass `null` to clear. Failing periods surface in `layerz_read` under `health` — non-blocking."
        -      },
        -      "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_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. Pass null to clear (back to fit-to-data)."
        -      },
        -      "role": {
        -        "description": "Change the item role. Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "enum": [
        -          "assumption",
        -          "formula",
        -          "callup",
        -          "balance",
        -          "section",
        -          "chart",
        -          "dashboard",
        -          "kpi",
        -          "mini_table"
        -        ],
        -        "type": "string"
        -      },
        -      "row_break": {
        -        "description": "dashboard-child line break: start this widget on a fresh grid row",
        -        "type": "boolean"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -        ],
        -        "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"
        -      },
        -      "chart_type": {
        -        "enum": [
        -          "line",
        -          "bar",
        -          "area",
        -          "bridge"
        -        ],
        -        "type": "string"
        -      },
        -      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -        "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. Use 'total' to chart a list total 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": "Business watchpoint. `assert` is a boolean expression in the formula language; the reserved token `value` is this item's computed value (a leading comparator like \"== 0\" implies it). Values are evaluated rounded to 2 decimals, so \"== 0\" already absorbs sub-0.005 residuals (a balance netting to 1e-11 reads as 0 and passes); use a wider tolerance (\"ABS(value) < 1\") only to ignore a materially larger gap — a sub-cent tolerance adds nothing over \"== 0\". Failing periods surface in `layerz_read` under `health` — non-blocking.",
        -        "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_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. Pass null to clear (back to fit-to-data)."
        -      },
        -      "role": {
        -        "description": "Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -        "enum": [
        -          "assumption",
        -          "formula",
        -          "callup",
        -          "balance",
        -          "section",
        -          "chart",
        -          "dashboard",
        -          "kpi",
        -          "mini_table"
        -        ],
        -        "type": "string"
        -      },
        -      "row_break": {
        -        "description": "dashboard-child line break: start this widget on a fresh grid row",
        -        "type": "boolean"
        -      },
        -      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -      },
        -      "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"
        -            ],
        -            "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"
        -          },
        -          "chart_type": {
        -            "enum": [
        -              "line",
        -              "bar",
        -              "area",
        -              "bridge"
        -            ],
        -            "type": "string"
        -          },
        -          "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        -            "maxLength": 50,
        -            "type": "string"
        -          },
        -          "formula": {
        -            "maxLength": 2000,
        -            "type": "string"
        -          },
        -          "inputs": {
        -            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        -            "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. Use 'total' to chart a list total 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": "Business watchpoint. `assert` is a boolean expression in the formula language; the reserved token `value` is this item's computed value (a leading comparator like \"== 0\" implies it). Values are evaluated rounded to 2 decimals, so \"== 0\" already absorbs sub-0.005 residuals (a balance netting to 1e-11 reads as 0 and passes); use a wider tolerance (\"ABS(value) < 1\") only to ignore a materially larger gap — a sub-cent tolerance adds nothing over \"== 0\". Failing periods surface in `layerz_read` under `health` — non-blocking.",
        -            "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_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. Pass null to clear (back to fit-to-data)."
        -          },
        -          "role": {
        -            "description": "Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        -            "enum": [
        -              "assumption",
        -              "formula",
        -              "callup",
        -              "balance",
        -              "section",
        -              "chart",
        -              "dashboard",
        -              "kpi",
        -              "mini_table"
        -            ],
        -            "type": "string"
        -          },
        -          "row_break": {
        -            "description": "dashboard-child line break: start this widget on a fresh grid row",
        -            "type": "boolean"
        -          },
        -          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        -          },
        -          "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_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"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "aggregation": {
        +        "enum": [
        +          "sum",
        +          "average",
        +          "stock"
        +        ],
        +        "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"
        +      },
        +      "chart_type": {
        +        "enum": [
        +          "line",
        +          "bar",
        +          "area",
        +          "bridge"
        +        ],
        +        "type": "string"
        +      },
        +      "check": {
        +        "anyOf": [
        +          {
        +            "properties": {
        +              "tolerance": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Flag the line as a control, judged on its OWN value: a plain amount must stay 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. Pass `null` to remove the check. Failing periods surface in `layerz_read` under `health` — non-blocking."
        +      },
        +      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "maxLength": 50,
        +        "type": "string"
        +      },
        +      "formula": {
        +        "maxLength": 2000,
        +        "type": "string"
        +      },
        +      "inputs": {
        +        "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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_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. Pass null to clear (back to fit-to-data)."
        +      },
        +      "role": {
        +        "description": "Change the item role. Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "enum": [
        +          "assumption",
        +          "formula",
        +          "callup",
        +          "balance",
        +          "section",
        +          "chart",
        +          "dashboard",
        +          "kpi",
        +          "mini_table"
        +        ],
        +        "type": "string"
        +      },
        +      "row_break": {
        +        "description": "dashboard-child line break: start this widget on a fresh grid row",
        +        "type": "boolean"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +      },
        +      "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"
        +        ],
        +        "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"
        +      },
        +      "chart_type": {
        +        "enum": [
        +          "line",
        +          "bar",
        +          "area",
        +          "bridge"
        +        ],
        +        "type": "string"
        +      },
        +      "check": {
        +        "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +      },
        +      "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +        "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": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +        "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. Use 'total' to chart a list total 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_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. Pass null to clear (back to fit-to-data)."
        +      },
        +      "role": {
        +        "description": "Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +        "enum": [
        +          "assumption",
        +          "formula",
        +          "callup",
        +          "balance",
        +          "section",
        +          "chart",
        +          "dashboard",
        +          "kpi",
        +          "mini_table"
        +        ],
        +        "type": "string"
        +      },
        +      "row_break": {
        +        "description": "dashboard-child line break: start this widget on a fresh grid row",
        +        "type": "boolean"
        +      },
        +      "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +      },
        +      "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"
        +            ],
        +            "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"
        +          },
        +          "chart_type": {
        +            "enum": [
        +              "line",
        +              "bar",
        +              "area",
        +              "bridge"
        +            ],
        +            "type": "string"
        +          },
        +          "check": {
        +            "description": "Flag the line as a control, judged on its OWN value at every period: a plain amount must stay within `tolerance` of 0 (ABS(value) < tolerance, default 1, on values rounded to 2 decimals — a balance netting to 1e-11 passes); a formula that is itself a comparison / AND / OR / NOT (e.g. \"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"
        +          },
        +          "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). An unknown name is REJECTED with code UNKNOWN_FORMAT listing what is available; prefer `percent` over legacy `\"%\"`. Full catalog with each excel_format and rendered positive/negative/zero examples (e.g. `default` = dash-for-zero accounting style vs `integer` = plain 0): MCP resource `format-spec://reference`. See docs/mdk-format.md § 4.4.",
        +            "maxLength": 50,
        +            "type": "string"
        +          },
        +          "formula": {
        +            "maxLength": 2000,
        +            "type": "string"
        +          },
        +          "inputs": {
        +            "description": "Direct contributors override (item UIDs or same-batch temp ids). Useful for `balance` items, which carry no formula but can declare the flows that roll into the stock; for `formula` items inputs are derived from the expression, so set this only to override that derivation.",
        +            "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. Use 'total' to chart a list total 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_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. Pass null to clear (back to fit-to-data)."
        +          },
        +          "role": {
        +            "description": "Role of the item — pick by intent. assumption: an input/driver you own (set value/values/timeline_values; the only role a Dataset can override). formula: a computed transformation (set formula). formula with NO expression + children: a Σ aggregator that sums its children (a subtotal VALUE — use a nested section instead when you only need structural grouping). callup: a typed mirror of ONE source whose value flows into its parent (set source) — for balance flows and surfacing a value in a section/subtotal, NOT for arithmetic (reference the source directly inside a real formula). balance: a rolling stock (set opening_balance; sums its callup-child flows). section: structural container, no value. dashboard/chart/kpi/mini_table: presentational. A formula is an aggregator XOR a transformation (never both expression AND children). A single bare reference written as a formula is auto-posed as a callup mirror.",
        +            "enum": [
        +              "assumption",
        +              "formula",
        +              "callup",
        +              "balance",
        +              "section",
        +              "chart",
        +              "dashboard",
        +              "kpi",
        +              "mini_table"
        +            ],
        +            "type": "string"
        +          },
        +          "row_break": {
        +            "description": "dashboard-child line break: start this widget on a fresh grid row",
        +            "type": "boolean"
        +          },
        +          "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 — key is the element UID, label, OR a `list_create` temp id from the SAME batch (temp ids do not survive to a later batch; use the label/UID then). Non-list item: either a full series keyed by a canonical grain (`monthly`/`quarterly`/`yearly`/`constant`, the import path) OR a sparse per-period patch keyed by period id (e.g. `{\"2026-06\": -119.19}`) that overwrites only the named cells and leaves the rest — the future projection — intact. 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"
        +          },
        +          "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_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"
        +  }
        +]
    • Changedlayerz_read1 field changed
      • changedInput schema / properties / health / description
        Previous value: -"Also return the `health` block: non-blocking business-monitor violations. Monitors are evaluated at the finest active grain. `with_values: true` already includes `health` when the model has monitors; set this to get `health` without the full value series."New value: +"Also return the `health` block: non-blocking check violations (lines flagged `check`). Checks are evaluated at the finest active grain. `with_values: true` already includes `health` when the model has checks; set this to get `health` without the full value series."
  10. 42 tool updates
    • First observedlayerz_build_from_blueprint
    • First observedlayerz_create_model
    • First observedlayerz_create_upload_url
    • First observedlayerz_delete_branch
    • First observedlayerz_delete_integration
    • First observedlayerz_delete_mapping
    • First observedlayerz_dependencies
    • First observedlayerz_diff
    • First observedlayerz_export
    • First observedlayerz_external_ref
    • First observedlayerz_external_ref_status
    • First observedlayerz_get_custom_instructions
    • First observedlayerz_get_finance_md
    • First observedlayerz_get_model
    • First observedlayerz_get_template
    • First observedlayerz_history
    • First observedlayerz_history_for_item
    • First observedlayerz_import_branch
    • First observedlayerz_import_mapping_template
    • First observedlayerz_list_branches
    • First observedlayerz_list_integrations
    • First observedlayerz_list_mappings
    • First observedlayerz_list_models
    • First observedlayerz_list_shares
    • First observedlayerz_list_templates
    • First observedlayerz_list_transactions
    • First observedlayerz_manage_integration
    • First observedlayerz_match_items
    • First observedlayerz_parse_file
    • First observedlayerz_patch
    • First observedlayerz_pin_version
    • First observedlayerz_promote_template
    • First observedlayerz_read
    • First observedlayerz_restore_version
    • First observedlayerz_revoke_share
    • First observedlayerz_set_custom_instructions
    • First observedlayerz_set_finance_md
    • First observedlayerz_set_mapping
    • First observedlayerz_share_model
    • First observedlayerz_unlink_external_ref
    • First observedlayerz_update_branch
    • First observedlayerz_validate_model

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    C
    maintenance
    Provides AI agents with deterministic, offline finance tools for commodity margin analysis, loan covenant compliance, invoice auditing, AP exception classification, and five-day close readiness.
    14
    2 npm
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables agents to synthesize multi-tab enterprise spreadsheet financial models, detect circular references, compile formula dependency DAGs with functions like SUMIFS/XLOOKUP/CAGR/NPV, and evaluate deterministic preview cell matrices.
    7
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Universal governance layer for AI agents — MCP-native, fail-closed, LNN interpretability. Governed receipts, IPFS audit proofs, and rollback for any agent in any framework.
    3
    60 npm
    Apache 2.0
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources