Understanding Pigment Modeling
Read this before any modeling task.
Mental Model
Pigment is an in-memory, sparse, multidimensional engine. An Application is a collection of typed blocks. Two orthogonal layers (Native Scenarios for what-if sandboxes, Snapshots for frozen copies) apply across all blocks.
Invariants
These are never negotiable.
Structure
- Only dimension lists can be structural. Transaction lists never. Aggregate with
BY. - A metric cell = one item per structural dimension. Blank cells are not stored (sparsity).
- Every app with planning metrics gets a Version Dimension. Do not skip or defer.
- List Subsets delete data irreversibly on membership change. Prefer filters unless the use case is clear.
Naming and organization
- Never use
.,:,', or"in block names. Prefer ASCII. - Never place a block at the root level. Use numbered folders.
- Folders are inert. They affect discovery, not calculation.
Build order
- Calendar (verify/configure) → Dimensions → Version Dimension → Transaction Lists → Metrics (input, then calculated) → Tables → Boards. Always create prerequisites before dependents.
- Never recreate time dimensions. Reuse the app calendar.
Formula safety
- Never hard-code dimension item references for Time, Version, countries, or planning periods. Use a Dimension-typed input metric. Stable type/class/category items (e.g.
'FX Rate Types'."AVG") may stay hard-coded. - Never use
DATE()with literal year/month for period bounds. Use a Date-typed input metric. - When T&D is active: never use a disconnected dimension as the property type on a connected dimension. Ask the user about connectivity if unknown.
Structural changes on existing blocks
- A structural change (adding/removing a dimension, changing type) does not automatically propagate to the metrics that reference the changed one. Pigment aligns mismatched dimensions silently (broadcast/collapse) instead of failing, which can produce wrong numbers with no visible error. Before editing, use
tool:get_data_dependency_tree(directionSources) to trace back to the originating metric(s) and transaction list, so you know what grain of detail already exists upstream. Before declaring such a change done, usetool:get_data_dependency_tree(directionUsages) to find dependent formulas, thentool:validate_formula(withtarget.metric_id) on each to catch a silent mismatch — seeskill:writing-pigment-formulas("Structural Dimension Changes") for the full workflow. - Removing a dimension from a metric's structure is lossy and irreversible. Unlike adding a dimension, once the metric no longer stores that grain the historical detail cannot be recovered from the metric itself. Say so explicitly when proposing the change, even if the detail still exists upstream (e.g. on a source metric or transaction list).
Decisions the Agent Gets Wrong Most Often
When unsure about property types: do not default categorical fields to Text. If the values form a finite set that could become a slicing axis, make it a Dimension.




