insurance.sum-insured-average Unreviewed
Average clause settlement for underinsurance: the loss times sum insured over value at risk, capped at the loss.
1.0.1 · published 2026-10-03 by charlie · Anterra
Pinned by 22 tests, run in TypeScript, Python and Rust.
Unreviewed. This capability’s implementations agree in every language and pass its published test vectors, which were worked out from the official sources cited. But no qualified actuary has yet checked those vectors, or confirmed that the capability covers the cases it claims. Treat it as a draft. Do not use it for real people, money or decisions without your own expert review. Once a qualified reviewer signs off, this notice is replaced with their name, qualification and the date. Each new version needs fresh sign-off.
Not professional advice. This capability calculates insurance figures from published rules. It is a software component for developers, not financial advice. Rules change and every rate here has an effective date. Check that the dates cover your case. Verify results against the official sources listed in its README, and have an actuary review how you use it, before anyone relies on the output. Provided “as is” under its licence, without warranty.
What it does
Claim settlement under an average clause (the underinsurance, or "pro rata average", condition in UK property policies). If the sum insured is less than the value at risk, the policyholder is treated as their own insurer for the difference and is paid only that share of any loss:
payout = loss x sumInsured / valueAtRisk
For example
averageClauseSettlement(£40,000.00, £150,000.00, £200,000.00, 100%, half-up)→ payout £30,000.00, average applied true, insured proportion basis points 75%, shortfall £10,000.00 insured for 150,000 of 200,000: a 40,000 loss pays 30,000averageClauseSettlement(£40,000.00, £200,000.00, £200,000.00, 100%, half-up)→ payout £40,000.00, average applied false, insured proportion basis points 100%, shortfall £0.00 fully insured pays the lossaverageClauseSettlement(£40,000.00, £250,000.00, £200,000.00, 100%, half-up)→ payout £40,000.00, average applied false, insured proportion basis points 100%, shortfall £0.00 over-insured pays the loss, and the proportion stops at 100%
The function
The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.
export function averageClauseSettlement(loss: Money, sumInsured: Money, valueAtRisk: Money, conditionBasisPoints: number, mode: RoundingMode): AverageSettlement
| loss | Money | the loss, 0 up to the value at risk |
| sumInsured | Money | the sum insured on the policy, 0 or more |
| valueAtRisk | Money | the full value of the property at the time of the loss, more than 0 |
| conditionBasisPoints | int | average applies when the sum insured is below this share of the value: 10000 always, 7500 the special condition |
| mode | RoundingMode | how the averaged payout rounds to a minor unit |
| returns | AverageSettlement |
The type it declares, generated into your project
/** The payout after average and what the policyholder bears. */
export interface AverageSettlement {
readonly payout: Money;
readonly averageApplied: boolean;
/** sum insured over value at risk, rounded down, at most 10000 */
readonly insuredProportionBasisPoints: number;
/** loss minus payout */
readonly shortfall: Money;
}
Your code names it in one line, in the file that uses it
import { averageClauseSettlement } from "#fune/insurance.sum-insured-average@^1";
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { type RoundingMode, roundDiv } from "./math_round_div.ts"; ← from math.round-div ^1.0.0 · built alongside by fune
import { type Money, assertSameCurrency, money } from "./money_amount.ts"; ← from money.amount ^1.0.0 · built alongside by fune
import { type AverageSettlement } from "./insurance_sum_insured_average_types.ts";
/**
* Settle a claim under an average clause.
*
* A property insured for less than it is worth is paid only the share of the
* loss that the sum insured bears to the value at risk: insured for 75% of
* its value, it is paid 75% of any loss. With a special condition of average
* the clause only applies once the sum insured falls below that share of the
* value. The payout never exceeds the loss or the sum insured.
*/
export function averageClauseSettlement(
loss: Money,
sumInsured: Money,
valueAtRisk: Money,
conditionBasisPoints: number,
mode: RoundingMode
): AverageSettlement {
assertSameCurrency(loss, sumInsured);
assertSameCurrency(loss, valueAtRisk);
if (valueAtRisk.minor <= 0) {
throw new RangeError(`valueAtRisk must be more than zero, received ${valueAtRisk.minor}`);
}
if (loss.minor < 0) throw new RangeError(`loss must not be negative, received ${loss.minor}`);
if (sumInsured.minor < 0) throw new RangeError(`sumInsured must not be negative, received ${sumInsured.minor}`);
if (loss.minor > valueAtRisk.minor) throw new RangeError("loss must not exceed the value at risk");
if (!Number.isInteger(conditionBasisPoints) || conditionBasisPoints < 1 || conditionBasisPoints > 10000) {
throw new RangeError(`conditionBasisPoints must be from 1 to 10000, received ${conditionBasisPoints}`);
}
const averageApplied = sumInsured.minor * 10000 < valueAtRisk.minor * conditionBasisPoints;
let payout = loss.minor;
if (averageApplied) {
// A loss and a sum insured in pence multiply past 2^53, so divide in bigint
// and round the remainder the way roundDiv would.
const wide = BigInt(loss.minor) * BigInt(sumInsured.minor);
const value = BigInt(valueAtRisk.minor);
payout = Number(wide / value) + roundDiv(Number(wide % value), valueAtRisk.minor, mode);
}
payout = Math.min(payout, loss.minor, sumInsured.minor);
const c = loss.currency;
return {
payout: money(payout, c),
averageApplied,
insuredProportionBasisPoints: Math.min(roundDiv(sumInsured.minor * 10000, valueAtRisk.minor, "down"), 10000),
shortfall: money(loss.minor - payout, c),
};
}Install
fune build
With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and its 2 dependencies, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:
fune add insurance.sum-insured-average
The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./insurance.sum-insured-average-1.0.1-typescript.fune, or fetch it from a terminal with fune pull insurance.sum-insured-average@1.0.1:typescript.
The whole function, every language, is one file too: insurance.sum-insured-average-1.0.1.fune, 24,793 bytes, sha256 8e7b374a3bc1f1004bf949a8fbe45e47610e61258200987c46eb572ebace2363. It installs into a project of any language.
Customise it in your app
The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.
before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.
// fune: before insurance.sum-insured-average
after — your function gets the result and the arguments, and returns the final result.
// fune: after insurance.sum-insured-average
replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.
// fune: replace math.round-div in insurance.sum-insured-average
// fune: replace money.amount in insurance.sum-insured-average
step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show insurance.sum-insured-average --steps.
// fune: step insurance.sum-insured-average after <n|label>
Tests
A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.
| Case | Arguments | Expected | |
|---|---|---|---|
| insured for 150,000 of 200,000: a 40,000 loss pays 30,000 | £40,000.00, £150,000.00, £200,000.00, 100%, half-up | → | payout £30,000.00, average applied true, insured proportion basis points 75%, shortfall £10,000.00 |
| fully insured pays the loss | £40,000.00, £200,000.00, £200,000.00, 100%, half-up | → | payout £40,000.00, average applied false, insured proportion basis points 100%, shortfall £0.00 |
| over-insured pays the loss, and the proportion stops at 100% | £40,000.00, £250,000.00, £200,000.00, 100%, half-up | → | payout £40,000.00, average applied false, insured proportion basis points 100%, shortfall £0.00 |
| a total loss when underinsured pays the sum insured | £200,000.00, £150,000.00, £200,000.00, 100%, half-up | → | payout £150,000.00, average applied true, insured proportion basis points 75%, shortfall £50,000.00 |
| special condition of average at 75%: insured for 80% of value, no average | £40,000.00, £160,000.00, £200,000.00, 75%, half-up | → | payout £40,000.00, average applied false, insured proportion basis points 80%, shortfall £0.00 |
| special condition at 75%: insured for 70%, average applies in full proportion | £40,000.00, £140,000.00, £200,000.00, 75%, half-up | → | payout £28,000.00, average applied true, insured proportion basis points 70%, shortfall £12,000.00 |
| insured for exactly 75% under the 75% condition: not below it, so no average | £40,000.00, £150,000.00, £200,000.00, 75%, half-up | → | payout £40,000.00, average applied false, insured proportion basis points 75%, shortfall £0.00 |
| no average, but a loss above the sum insured is capped at it | £190,000.00, £160,000.00, £200,000.00, 75%, half-up | → | payout £160,000.00, average applied false, insured proportion basis points 80%, shortfall £30,000.00 |
| a third insured: 1,000.00 x 1/3 is 333.333..., half-up 333.33 | £1,000.00, £100,000.00, £300,000.00, 100%, half-up | → | payout £333.33, average applied true, insured proportion basis points 33.33%, shortfall £666.67 |
| the same rounded up | £1,000.00, £100,000.00, £300,000.00, 100%, up | → | payout £333.34, average applied true, insured proportion basis points 33.33%, shortfall £666.66 |
Show the other 12 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| two thirds: 666.666... half-up is 666.67 | £1,000.00, £200,000.00, £300,000.00, 100%, half-up | → | payout £666.67, average applied true, insured proportion basis points 66.66%, shortfall £333.33 |
| no loss pays nothing | £0.00, £150,000.00, £200,000.00, 100%, half-up | → | payout £0.00, average applied true, insured proportion basis points 75%, shortfall £0.00 |
| nothing insured pays nothing | £40,000.00, £0.00, £200,000.00, 100%, half-up | → | payout £0.00, average applied true, insured proportion basis points 0%, shortfall £40,000.00 |
| large values beyond 2^53 when multiplied: 9,000,000.00 of a 12,000,000.00 building insured for 10,000,000.00 | £9,000,000.00, £10,000,000.00, £12,000,000.00, 100%, half-up | → | payout £7,500,000.00, average applied true, insured proportion basis points 83.33%, shortfall £1,500,000.00 |
| a loss above the value at risk is refused | £3.00, £1.00, £2.00, 100%, half-up | → | error: loss must not exceed the value at risk |
| a zero value at risk is refused | £0.00, £1.00, £0.00, 100%, half-up | → | error: valueAtRisk must be more than zero |
| a negative sum insured is refused | £1.00, -£0.01, £2.00, 100%, half-up | → | error: sumInsured must not be negative |
| a negative loss is refused | -£1.00, £1.00, £2.00, 100%, half-up | → | error: loss must not be negative |
| a condition of 0 is refused | £1.00, £1.00, £2.00, 0%, half-up | → | error: conditionBasisPoints must be from 1 to 10000 |
| a condition above 100% is refused | £1.00, £1.00, £2.00, 100.01%, half-up | → | error: conditionBasisPoints must be from 1 to 10000 |
| a fractional condition is refused | £1.00, £1.00, £2.00, 75.005%, half-up | → | error: conditionBasisPoints must be from 1 to 10000 |
| a sum insured in another currency is refused | £1.00, €1.00, £2.00, 100%, half-up | → | error: currency mismatch |
More from the author
So a building worth 200,000 insured for 150,000 (75%) is paid 30,000 on a 40,000 loss, not 40,000. The payout is never more than the loss (over- insurance does not pay a profit) or the sum insured (a total loss when underinsured pays the sum insured).
## The condition
`conditionBasisPoints` says when average applies at all:
- **10000**: pro rata average, whenever the sum insured is below the value. - **7500** (or 8500 and so on): a *special condition of average*, where average applies only if the sum insured is below that share of the value at risk; above it, losses are paid in full up to the sum insured. When it applies, it applies in the full proportion (sum insured / value), which is the usual UK wording. Some wordings instead scale by sum insured over the threshold value; that is a different clause and not this one.
The test is strict: insured for exactly 75% under a 75% condition is not below it, so no average.
## Details
- The payout rounds to the minor unit in the caller's mode. The product of a loss and a sum insured in pence can pass 2^53 (a 12,000,000.00 building), so it is divided exactly as a big integer (i128 in Rust) before rounding. - `insuredProportionBasisPoints` is sum insured over value at risk, rounded down and capped at 10000, for display ("insured for 83.33% of value"). - `valueAtRisk` is the full reinstatement (or market) value at the time of the loss, on whatever basis the policy says; the loss may not exceed it. - Apply the excess with `insurance.excess-apply`; whether the excess comes off before or after average is a matter of the policy wording.
## Before you rely on this
**Not professional advice.** This capability calculates insurance figures from published rules. It is a software component for developers, not financial advice. Rules change and every rate here has an effective date. Check that the dates cover your case. Verify results against the official sources listed above, and have an actuary review how you use it, before anyone relies on the output. Provided "as is" under its licence, without warranty.
**Unreviewed.** This capability's implementations agree in every language and pass its published test vectors, which were worked out from the official sources cited. But no qualified actuary has yet checked those vectors, or confirmed that the capability covers the cases it claims. Treat it as a draft. Do not use it for real people, money or decisions without your own expert review. Once a qualified reviewer signs off, this notice is replaced with their name, qualification and the date. Each new version needs fresh sign-off.
1.0.1 marks it unreviewed. The code and the tests are unchanged.
Files
| Path | Bytes |
|---|---|
| README.md | 3,059 |
| impl/python.py | 2,135 |
| impl/rust.rs | 3,332 |
| impl/typescript.ts | 2,377 |
| vectors.json | 9,352 |