Version 0.6-draft. The tests will change before version 1. Every change is listed in CHANGELOG.md.

FPABench times what a planning team does every day. It loads actuals, types numbers into the plan, reads reports and changes the model. Each test does one of these to the model.

FileWhat it holds
README.mdThe tests, for people
tests.jsonThe same tests for the runner, with exact cells, values and expected results
method.mdHow the tests are timed, repeated, reset and checked

How a test works

Every load, write and model change ends with a proving read. The timer stops when that read returns the right answer. A fast wrong answer is a failure.

Most writes and some reads pick their cells at random. The test gives a rule, such as "a customer in the biggest customer group of its country, a SKU it buys, a plan month". A seed picks among the matching cells. The same rule works at every data size. Published runs use a public seed. A check run uses a second, unpublished seed, so a system cannot be tuned for the published cells.

Writes go to the FC 6+6 version unless a test says otherwise. Its plan months are Y2026 M7 to M12.

Each test expects one of three kinds of result.

KindMeaningExample
ValueThe reference program's exact answerThe company P&L for FC 6+6
DeltaA change the test states1,000 more in OPEX lowers EBIT by 1,000
UnchangedA value that must not moveEBIT of a country the write cannot reach

method.md has the full rules for checking answers.

Loads

IdTestProving readExpected result
L1Initial load. The ERP export, master data, planner inputs and version flags, from an empty system.EBIT EUR OUT by country, version and monthValue. Every check equals its published value.
L2Monthly close. Load the actuals of Y2026 M7, then close M7 in the Actual version.EBIT OUT of Actual, Y2026 M7Value. CHECK Import Total is 0.
L3Change a weight in master data. One SKU's unit weight.Logistics Cost of the SKU's brandValue. EBIT OUT is unchanged.

L2 loads the increments/close-2026-07 folder of the dataset.

Writes

IdTestProving readExpected result
W1Type one volume. One customer, SKU and plan month.EBIT OUT of the countryValue
W2Paste 1,000 volumes in one country, across the six plan months, in one transaction.Volume of the country over the plan monthsDelta. The sum of the changes.
W3Change a rebate rate of one customer group and month.EBIT OUT of the countryDelta. Rate change × the group's invoice sales.
W4Raise a brand's price for the year.Gross Sales of the brandDelta. × (1 + new) / (1 + old) in plan months.
W5Change a planning exchange rate of one currency and month.COGS of that country and monthDelta. × new rate / old rate.
W6aChange a warehouse's cost. It is allocated to customers.EBIT OUT of the countryDelta. EBIT falls by the change.
W6bChange an office's cost. It is not allocated.EBIT OUT of the countryDelta. EBIT falls by the change.
W7Set a yearly target for one customer group and category. The model spreads it down.Volume of the group and categoryValue
W8Flip a yearly bonus. Move a group's growth threshold across its growth. The group's bonus rate is above 0.Growth Bonus of the group for the yearDelta. Bonus rate × the year's invoice sales.
W9Copy a version. FC 6+6 into What-if, then change three inputs.The What-if P&LValue

W6a and W6b write the same kind of cell. W6a moves thousands of allocated cells, and W6b moves one total. An engine that recalculates only what a change reaches does far less work for W6b.

W9 waits on the model for a way to copy a version.

Reads

IdReadAnswer size
R1Company P&L. PL EUR OUT by line and month.13 × 12
R2aP&L by brand. PL EUR OUT by line and brand.13 × brands
R2bP&L by channel. PL EUR OUT by line and channel.13 × 6
R2cP&L by country, in its own currency. PL OUT by line and country.13 × countries
R3Plan against last year. PL EUR OUT by line for Budget, FC 6+6 and last year's actuals.13 × 3
R4Ratios. The 18 KPI measures by country and version.18 × countries × 5
R5Drill to the detail. The gross-to-net lines by customer and SKU for one customer group, in M7.12 × the group's rows
R6Margin by product attributes. Gross Margin by country, category and price tier.small
R7Top customers. The 100 largest by Contribution Margin III, in one country.100
R8Open the model. Start the system and read EBIT EUR OUT.1

Reads cover FC 6+6 and Y2026 unless they say otherwise. An amount in a local currency is never added across countries.

Model changes

IdChangeProving readExpected result
M1Change a formula. Handling weight no longer weighs chilled and frozen goods more.Logistics Cost by brand and countryValue. EBIT OUT is unchanged.
M2Add a customer to a customer group, with a typed volume.Volume of the groupDelta. The typed volume.
M3Move a customer to another group in the same country.Gross Sales of both groupsValue. Actual totals by country are unchanged.
M4Allocate one more cost. Marketing staff costs are spread to customers and brands.Contribution Margin III by countryDelta. It falls by what the pool allocated. EBIT OUT is unchanged.

Checks without a timer

IdCheckExpected result
C1Type a volume into a closed month.Nothing changes.
C2Read every CHECK variable.Each equals its published value.
C3Read another country's EBIT OUT right after each W1 write.Unchanged