The brief. A new submission lands on your desk: Léman Assurances SA (Lausanne), Personal Accident XL 2027, one layer 3m xs 2m at 6.5% rate on line, share offered 100%, subject premium 18m — and no stated loss ratio anywhere in the pack. Derive what can be derived; return null for what cannot. The battery fails you for inventing a zero.

This is the null-honesty principle from Lesson 1 at working size, and it is the exact behaviour of the product's SubmissionMetrics scope: the combined ratio is derived only when all four components are on file — stated loss ratio, brokerage, ceding commission, expense ratio. A missing figure must surface as a data-quality referral to the Head of Line of Business (Lesson 2 turns that into a rule), never as CR = 0 — which would be the most aggressive possible stance taken on the worst possible data.

The rules

  1. Premium100 must still work: 195,000 (0.065 × 3m). Missing economics never block premium math.
  2. CombinedRatio returns double? — the sum of all four components when all are present, else null.
  3. With brokerage 0.10 and expense 0.06 on file but loss ratio absent, the answer is null — and the battery's referral line must read "Data-quality referral → Head of LoB".
  4. A control case with loss ratio 0.70 on file must yield 0.86.

Your workbench

using MeshWeaver.Layout;
using MeshWeaver.Layout.Composition;
using MeshWeaver.Utils;

record Pack(string Name, double Limit, double RateOnLine, double? LossRatio, double? Brokerage, double? CedingCommission, double? ExpenseRatio);

// YOUR METRICS — mirror the product's SubmissionMetrics scope.
static double Premium100(Pack p)
    => 0.0;                 // TODO: rate on line × limit — never blocked by missing economics.

static double? CombinedRatio(Pack p)
    => 0.0;                 // TODO: lr + brokerage + ceding commission + expense — ONLY when all four are on file, else null.

var leman = new Pack("Léman PA XL 2027 — as received", 3_000_000, 0.065, null, 0.10, 0.0, 0.06);
var control = new Pack("Control — with LR 0.70 on file", 3_000_000, 0.065, 0.70, 0.10, 0.0, 0.06);

var premium = Premium100(leman);
var crLeman = CombinedRatio(leman);
var crControl = CombinedRatio(control);

var premiumOk = Math.Abs(premium - 195_000) < 0.5;
var lemanOk = crLeman is null;
var controlOk = crControl is double c && Math.Abs(c - 0.86) < 1e-9;

Controls.Stack
    .WithView(Controls.H4($"Null-honesty battery — {(premiumOk ? 1 : 0) + (lemanOk ? 1 : 0) + (controlOk ? 1 : 0)}/3 checks green"))
    .WithView(Controls.Markdown(
        $"- Premium @100% = **{premium:N0}** (must be 195,000) {(premiumOk ? "✓" : "✗")}\n" +
        $"- Léman CR = **{(crLeman is double v ? v.ToString("P0") : "null")}** (must be null) {(lemanOk ? "✓" : "✗")} — " +
        (lemanOk ? "**Data-quality referral → Head of LoB**" : "an invented figure would decide a deal on data nobody supplied") + "\n" +
        $"- Control CR = **{(crControl is double w ? w.ToString("P0") : "null")}** (must be 86%) {(controlOk ? "✓" : "✗")}"))

The stub fails the Léman check on purpose: it returns 0.0, which is the aggressive-zero bug. Your fix is not a bigger formula — it is refusing to answer.


All three green? Reveal the solution — the pattern-match that keeps null null.

← Lesson 1 exercises · Lesson 1 — The submission

Reconnecting…
The connection to the server was interrupted. Trying to restore it…
Trying again…
The connection could not be restored. Reloading the page…
The server was updated. Reloading the page to pick up the latest version.