The platform

An engine that speaks your business

Six chapters, eighteen mechanisms: what each one does for a planner, how it is built, and what it was measured doing. Nothing on this page is an adjective.

Every number carries its framing: measured in our lab, on our own test data.The full table, with caveats

Chapter 01

Your vocabulary is the model

There is no item table to bend your business into. Dimensions, levels, hierarchies and granularity are data, and every measure decides for itself how it rolls up and how it spreads down.

Your business’s words, not ours.

Dimensions, levels, hierarchies and granularity are data, not schema, so adding a channel, a demand stream, a supplier axis or a finer grain is a metadata change, with no migration and no downtime. A grain is any combination of dimension and level, with no limit on how many; the levels are named generically underneath and wear your display names on top.

Hierarchies can be alternate, ragged, shared and effective-dated, so a re-categorisation last year doesn’t quietly rewrite last year’s history. The whole model is authored in the Designer, through the same doors the rest of the product uses.

The category patternEvery dimension a planning tool hard-codes is a customisation it pre-sells to every future client, which is why adding a channel or a demand stream becomes a project. Fixed dimensionality is the single most expensive early mistake in this category.

The Designer Studio’s hierarchy canvas: a product dimension’s roll-up path from the top level to the leaf, with attributes dragged into it.The Designer Studio’s hierarchy canvas: a product dimension’s roll-up path from the top level to the leaf, with attributes dragged into it.
Designer StudioThe roll-up path from top to leaf, with attributes dragged into it, built from the interface, no code.Real screens on a demo world; the brands are fictional.

Plan where you think. It lands where it must.

Every measure declares how it spreads: by recent sales, by assortment, evenly, proportionally, or by a rule you author. And every roll-up names the hierarchy it rolls along. Two measures in the same group can flow differently, because spreading is a property of the measure, not of the table.

Locked cells stay locked, the totals still tie, and the grid shows you exactly which cells a spread touched. Cross-grain consensus is computed at a declared grain, flowed down and mass-conserved, at the gate, not by convention.

The category patternGrid spreading is where planning tools quietly lose money: a spread that ignores locks, or conserves mass only sometimes, is a number nobody can defend in a meeting.

A measure’s aggregation and spreading rules in the Designer: aggregation up, aggregation over time, the hierarchy it rolls along and the disaggregation basis.A measure’s aggregation and spreading rules in the Designer: aggregation up, aggregation over time, the hierarchy it rolls along and the disaggregation basis.
Designer StudioAggregation up, aggregation over time, the hierarchy and the disaggregation basis, per measure, never hardcoded.

Chapter 02

The engine

A contest per series picks the model and names why. The fact store is an adapter, so the same core runs on a laptop and on a billion rows. And speed is a budget that fails the build, not an adjective.

A contest for every series, every cycle.

Simple methods, classical statistics, intermittent-demand methods and machine learning all compete on each series’ own history, scored on the same accuracy definition used everywhere else in the product. The winner is named on the grid, the scoreboard shows every challenger and the margin, and the ranges (P10 / P50 / P90) come from the model that won, not from a rule of thumb applied afterwards.

Forecasting happens at more than one level by design; each level is a configuration object, not a special case. The tournament itself owns no arithmetic. It is a frame that reads policy, routes the entrants, scores them and writes the verdict as measures.

36,220

series classified in one full-portfolio contest, run as a governed job

31,151

series judged, 1,090 skipped honestly, 0 refused

108.9min

to publish 800k forecast cells and 1.16M verdict cells

On a demo tenant. We quote the throughput; the run’s accuracy figure is not a claim.

The category patternOne global model, or a model chosen by a consultant at go-live and never revisited, is the category norm. A contest re-run every cycle, whose scoreboard is ordinary filterable data, is the difference between a forecast you inherit and one you can interrogate.

The model contest scoreboard rows: each method that competed on a series, with its rank, its error and the margin to the champion.The model contest scoreboard rows: each method that competed on a series, with its rank, its error and the margin to the champion.
The model contest scoreboard rows: each method that competed on a series, with its rank, its error and the margin to the champion.The model contest scoreboard rows: each method that competed on a series, with its rank, its error and the margin to the champion.
Model contestThe scoreboard rows: method, rank and error for each entrant, the winner and the runner-up named.

One core, from a single site to a billion rows.

The fact store is an adapter, not a dependency: embedded columnar on a laptop, a scale-out column store in production, and a cloud-warehouse adapter designed behind the same contract, with Apache Arrow as the interchange in between. The model, the math and the screens do not change when you move. The configuration does. Two adapters are in the tree today; the cloud-warehouse adapter is designed and named in the architecture, and is built with the first customer who runs on one.

The swap is proven, not promised: both storage engines return identical totals at both scales, and one configuration value is the whole switch, zero caller changes. Two live demo tenants were re-materialised across engines at 208.5M cells, about 2M cells per second, parity exact.

1,003,750,000

rows in one retail day-level fact table on the scale-out adapter: 2,500 items × 2,500 stores × 730 days

127.8ms

a workbench-shaped pivot page over that table, cold

missed our own 100 ms tight target by 28 %, and we recorded that

65.6ms

a 500-store × month drill on the same table

2.39Mrows/s

write throughput at billion-row scale, through the storage contract

Measured in our lab, on our own test data, never a customer benchmark. Not a production workload.

The category patternThe category answers “small customer” and “large customer” with two products, two price books and two roadmaps, or it forces a corner shop onto a data warehouse. One logical model with swappable storage is what makes a single product honest at both ends.

Every number, with what it measures and its caveat

Budgets, not adjectives.

Every performance claim we make is an assertion inside our test suite: a pivot page, a cell edit reaching its downstream measures, a cascade, each with a millisecond ceiling that fails the build when it is crossed. Hot paths stay inside the engine: no serialisation round-trips on an edit or a pivot load, and the orchestration language never loops over rows of math.

An edit is visible to you in well under half a second, and its downstream effects follow in tens of milliseconds.

70ms

a single cell edit reaching its downstream measures, the full stack, single-node setup

one edit, one tenant; not a live rule cascade, which is a different number

193 to 212ms

p95 for an editor under sustained load on the scale-out setup: 25 edits/s + 10 reads/s for 60 s, run twice, zero failures

p50 10 ms; inside our 500 ms limit

54 / 439

backend test files that assert a timing bound: budgets are tests

Measured in our lab, on our own test data, never a customer benchmark.

The category patternPlanning suites die at aggregation and spreading under real volume, and the usual answer is a nightly batch and a “please be patient” dialog. A budget that breaks the build is a different commitment from a benchmark in a slide.

Chapter 03

Nothing is a black box

Every number is traceable to its inputs, its formula or model, its version, and who or what produced it. The platform grades its own work, and nothing changes without a record.

Every number can be asked why.

Right-click a forecast and see what built it: the base level, each driver’s push up or down, the model that won and the margin it won by, and what changed since the last cycle. The explanation is of the number you clicked, always, declared by the rule that authored it, never inferred, and the same permissions that wall the grid wall the explanation, so it is never a side channel.

Where the arithmetic is exact we draw the waterfall. Where it is a proportional share we say so in words instead of drawing one that would lie, and we tell you how much of an aggregate a breakdown actually stands on, never implying coverage it does not have.

9.2 % → 3.7 %

median gap between the explainer and the winning model’s forecast: the explanation got twice as faithful

worst-5 % tail 26 % → 17 %; on a demo tenant; a fidelity figure, not an accuracy claim

The category patternThe category’s most expensive failure is trust, not accuracy: a black-box engine gets overridden until the tool is a spreadsheet’s data source. Explainability here is architecture: built in, not reported on.

The cell’s own right-click menu over a forecast: explain this cell, what built this number, what changed here.The cell’s own right-click menu over a forecast: explain this cell, what built this number, what changed here.
What built this number?The cell’s own menu: the model’s words, the driver waterfall and the lineage, one click away.
The explanation for one forecast cell: the base level, each driver’s signed contribution and the explained forecast, read at the cell’s own grain.The explanation for one forecast cell: the base level, each driver’s signed contribution and the explained forecast, read at the cell’s own grain.
What built this number?The signed driver waterfall for one cell: base, drivers, explained forecast.

It will tell you when it was wrong. It will tell you when you were.

Accuracy, bias and forecast value added are computed every cycle at whatever level you pivot to, from one definition used identically on every screen: one metric dictionary, in code, that forbids a ratio of aggregates. If a manual adjustment reduced accuracy, that shows up too, quietly, with the number.

Cycles are frozen as governed snapshots, so accuracy at every lag is measured against the promise that was actually made, and the movement from one plan to the next is bridged term by term, with the bars tying arithmetically.

The category patternA suite that reports only its wins teaches planners to distrust it. A platform that will tell you your own override cost accuracy is the one you can let near a commitment.

Why it moved: the plan-movement waterfall from the earlier vintage to this one: overrides, new and dropped coverage, unattributed movement, net change.Why it moved: the plan-movement waterfall from the earlier vintage to this one: overrides, new and dropped coverage, unattributed movement, net change.
Why it movedThe plan-movement waterfall: overrides, new and dropped coverage, unattributed movement, net change.

Nothing changes without a record.

Configuration is versioned and diffable, plan edits carry who, when, what-from and what-to, and a published cycle is an immutable snapshot you can compare against, value by value, three ways. Every governed run carries its own scope record: what it ran on, with which parameters, and what it wrote.

Upgrades arrive as a three-way diff against your own customisations, with conflicts named rather than overwritten. Change sets roll back as a unit when something in them fails.

The category pattern“Configuration as an undocumented state of the production system” is the category’s quiet default, and it is why upgrades are feared. Versioned configuration with diffs is configuration managed like code without being code.

A governed run’s scope record: the named set it ran on, its parameters and its footprint.A governed run’s scope record: the named set it ran on, its parameters and its footprint.
Jobs & runsThe run’s scope: the named set it ran on, its parameters and its footprint.

Chapter 04

Everything is a policy

Every behaviour of the engine is a switch with a dial, set once at whatever level you choose. Everything that changes the business is a screen. And one filter grammar serves every grid, every run and every access rule.

Every setting is yours, at the level you pick.

Cleansing, outlier treatment, stockout handling, launch curves, phase-out fences: each is a switch with a dial, pinned at a category, a region, a channel or a single item. Set it once; everything underneath inherits it; one item can differ, on the record with a reason. The layers resolve in a fixed order: package default, tenant default, segment, series pin, and the page tells you which one a value is riding, rather than hiding it.

In the demand module the same policies sit on a rail beside the plan: each setting a switch with the stages it runs at, a badge saying whether it was set here, inherited or a package default, and what a change here reaches. Then one verb, Apply at this level, with a dry-run preview before anything commits. A policy family the platform has never seen lands as a plain metadata write, no release.

14ms

the same lifecycle run with the setting off

169ms

with the setting on, off provably skips, pinned byte-identically per setting

32ms

the footprint ladder that reports what a change reaches

Single-node setup, after the adversarial fix pass. Measured in our lab, on our own test data, never a customer benchmark.

The category patternIn the legacy pattern, engine behaviour is a consultant’s configuration job or a support ticket; “we don’t handle intermittent demand that way” is an answer you live with. Here it is a toggle, and the off path is proven to cost nothing.

The Policy Studio: a policy family’s named setups, each option typed and described, riding a default until it is set.The Policy Studio: a policy family’s named setups, each option typed and described, riding a default until it is set.
The Policy Studio: a policy family’s named setups, each option typed and described, riding a default until it is set.The Policy Studio: a policy family’s named setups, each option typed and described, riding a default until it is set.
Policy StudioA family’s named setups, each option typed, described and riding a default until set.
The precedence layers a policy resolves through, weakest first: package default, tenant default, segment, series pin.The precedence layers a policy resolves through, weakest first: package default, tenant default, segment, series pin.
Policy StudioThe named layers a policy resolves through, weakest first. The highest rank wins, and a pin carries a reason.

If it changes the business, it’s a screen.

Measures, formulas, rules, pages, filters, policies, action buttons and model bindings are all authored in the product and versioned like everything else. Every code artifact, formulas, rules, steps, saved SQL, plug-in source, is visible, editable and where-used traceable in the interface; nothing runs that an administrator cannot see. The friendly forms and the advanced JSON edit one truth and round-trip both ways.

Every planning screen in the product is rendered from that same metadata. There are no special pages we built for ourselves. The whole application renders from one route.

The category patternThe consulting bill in this category is mostly configuration that the vendor kept for itself. A configurability ladder that ends in a governed SQL console is a statement that there is nothing to hide and nothing to gatekeep.

Active rules in the Algorithm Studio: each rule with its live formula, its target, the slice it edits and its on-off switch.Active rules in the Algorithm Studio: each rule with its live formula, its target, the slice it edits and its on-off switch.
Algorithm StudioEach rule with its expression, its edit slice and its live switch, the jump to its code one click away.

The configurability ladder

Five rungs, from the planner’s formula to the administrator’s governed console. You climb only as far as the question needs.

  1. Formulas and named sets

    a planner or an analyst

    A measure defined from other measures; a saved selection, "top 100 by revenue in the North region, excluding discontinued", that every grid, run, policy and access rule can reuse.

  2. Rules

    an analyst or an administrator

    A live rule with a target, an expression and the slice it edits, bounded or open in time, switched on and off from the interface, versioned like everything else.

  3. Procedures and action buttons

    an administrator

    A governed sequence of steps behind a button with a typed parameter form, so a routine becomes one click with its inputs validated.

  4. Plug-ins

    your data scientists and engineers

    A model, a solver, a feature or a custom step registered through one contract: sandboxed, resource-limited, permissioned and lineaged, competing on the same footing as the built-ins.

  5. The governed SQL workspace

    an administrator, when the forms run out

    Read-only by default, audited always, walled by the same permissions as every other door. The last rung is a statement that there is nothing to hide.

Define it once. Use it everywhere.

“Top 100 by revenue in the North region, excluding discontinued” is a named set, and that same set filters a grid, scopes a forecast run, targets a policy, drives an alert queue and defines who can see the data. Sets compose: attribute predicates, hierarchy operations, explicit lists, set algebra, measure-driven filters and a moving now-window, dynamic or snapshotted, compiled by the same family that compiles formulas.

One vocabulary for analysis, execution and access. Nothing to re-learn per screen.

The category patternThe legacy pattern grows a different filter language per surface: one for reports, one for jobs, one for security, and the three drift. One grammar means a saved selection is portable across the whole product, including who is allowed to see it.

How the same grammar walls your data
The view filter rail on the consensus plan: members picked at any level, the picks saved as a segment that the chart and the worksheet both follow.The view filter rail on the consensus plan: members picked at any level, the picks saved as a segment that the chart and the worksheet both follow.
Consensus planThe view filter rail: pick members at any level, save the picks as a segment. The chart and the worksheet follow together.

Chapter 05

Open by design

A module is configuration, not a release. Your model competes through the same door as ours. The platform describes itself so software can read it. And a what-if costs nothing to start.

The engine came first. The modules are configuration.

Dimensions, grains, measures, rules, pages, policies and model bindings are metadata, so a planning module is a versioned package you activate, diff and upgrade, not a release you wait for. Industry behaviour enters only as package content: policy rows, formulas, sets, bindings. If a package ever needs a behaviour the engine lacks, that becomes a named platform task first, never an engine fork.

Demand ships today on exactly the same core that will carry inventory, supply and S&OP. If building the second module required touching the core, the platform would not be finished.

59

metadata packages that make up the demand module: content, not engine code

8

swappable contracts the platform is built on

0

lines of module code to build a whole application from an empty install, through the product’s own doors

The category patternIn the legacy pattern a new module is a new product with a new schema and a new implementation. Here the second module costs the platform nothing, because the first one already proved the engine has no module-specific code in it.

Modules: what is available, what is by design

Your model, our contest, one contract.

Register a model or a solver and it competes exactly as ours do: same inputs, same backtest, same accuracy definition, same lineage record of which version produced which number. It runs sandboxed, resource-limited and permissioned, because “bring your own code” and “governed” have to be the same sentence. One contract covers forecast, solver, feature, segmentation and custom kinds; the built-ins are not privileged.

Integration runs both ways at the platform level: inbound connectors for files, databases, object storage, REST and streams, and governed outbound publish pipelines walled by the same permissions. Optimisation is expressed as metadata, with its shadow prices surfaced rather than hidden.

The category pattern“Bring your own model” in this category usually means a professional-services engagement. Here it is the same registration path the built-ins use, with the same sandbox, the same lineage and the same scoring.

The model library: every registered engine with capability chips derived from its own declaration, and what there is to tune.The model library: every registered engine with capability chips derived from its own declaration, and what there is to tune.
Model libraryEvery registered engine with what it can do and what there is to tune, the chips derived from the engine’s own declaration.

Built so software can read it, not just people.

Every capability is served by a documented door, and the model describes itself: policy catalogs, parameter schemas and level definitions are all readable metadata. Everything a person can do on a screen, a program can do through a door.

That is what makes assistive automation possible later without a rebuild, agent-ready by construction, and it is why the whole application renders from metadata today rather than from hand-built screens.

41

widget types, every planning screen composed from them

20

studio surfaces, each a registered system surface

1

route renders the entire planner application from metadata

Counts as of September 2026.

The category patternIn the legacy pattern the interface is the product and the API is an afterthought, so automation stops where the screens start. Here the screen is one client of the same door a program uses.

What-if, without the copy.

A scenario stores only the cells you changed, so creating one is instant and deleting one is instant. Branch a scenario off a scenario; compare them side by side, value by value; promote the parts you want into the plan. Conflicts are detected and surfaced, never silently merged.

Your permissions follow you inside a scenario, and promoting re-checks every cell. A scenario is never a bypass.

74ms

the scenario engine’s gate: the branch chain, the root rule, the cascade and the save walls, together

single-node setup

The category patternWhere scenarios are full plan copies, planners get three of them a quarter and a storage bill. Copy-on-write with ordered branch chains is what makes “try it” cheap enough to be a habit.

Chapter 06

Secure from row one

Isolation and permissions are in the first line of the schema, not a later project, and what you can see narrows what any report, run, scenario or explanation will show you.

Permissions that hold on every door.

Tenant isolation is enforced in the database itself: a connection that has not declared its tenant sees nothing and can write nothing; a forgotten call site fails safe. What a person may see narrows every grid, chart, run, export, scenario and explanation panel, by the same rule, with no side channels: effective data is always what the grants allow, intersected with the scope in hand: a scope can only narrow access, never widen it.

Isolation tiers are configuration, not code: shared schema, schema per tenant, database per tenant. We describe the posture; we do not claim a certification we have not obtained.

167ms

p95 to resolve and compile one person’s effective access across 1,000 users · 1,000 roles · 10,000 grants, cold

p50 143 ms, max 170 ms, flat, no cliff; p95 0.02 ms warm

482ms

to provision a schema-isolated tenant over HTTP: 94 tables at the same migration head, 89 policies in its own schema

single-node setup

Measured in our lab, on our own test data, never a customer benchmark.

The category patternSecurity bolted on late shows up as “export to a spreadsheet to share it”, the exact hole planning teams then live in. Grants that narrow every door, including the explanation panel and the SQL console, is the version that holds.

Security & trust: the posture in full

One skeleton, any vocabulary

The same core in four vocabularies

Retail, CPG, manufacturing and distribution do not get four products. They get one engine, and the words their business already uses on top of it.

  • Retail

    Department · class · subclass · item. Stores, channels and a retail calendar as their own axes.

    A plan authored at class × region × month spreads to the leaves by recent sales, and a locked store-week stays locked while the totals still tie. Retail merchandising is carried by the data model by design; it is not a module available today.

  • CPG

    Brand · category · pack size. Customer, channel and region on the demand side.

    Promotions and events are declared, dated, reusable drivers that the model contest judges rather than assumes. Consensus happens at the level the business meets, with the accuracy of every hand measured on one definition.

  • Manufacturing

    Items · sites · suppliers. Bill of material and routing as relationships in the model, not tables bolted on.

    We measured a 10,000-edge bill of material exploding in 26 ms on the single-node setup, multi-level, with quantity-per, scrap and effectivity. The engine already carries the hard part; the manufacturing module is built with our first manufacturing customer.

  • Distribution

    Depots · lanes · customers. A demand stream per channel, sourcing and lane relationships in the model.

    Demand planning is what ships today. Inventory and supply policies are carried by the engine by design: safety stock, service levels, make, buy and transfer. Those modules are next, each built with the first customer who needs it.

How an implementation runs

See the platform on your data

Bring your history, your hierarchies and your vocabulary. We model them in the Designer and show the engine working on them.

Request a demo

a working demo on your data · no commitment