lumnik. / scenarios All scenarios · Français

Every order says which version of the rule computed it

Goal Know, months later, which shipping rule computed each order.

Shipping is computed by a Kotlin script the hub's operator provides. In December it is free from 150.00. From 1 January, from 200.00. The operator replaces the script.

manifests/shipping-fee-v1.kts
// Operator-provided: the shipping fee of an order. Free shipping from 150.00 of goods.@Suppress("UNCHECKED_CAST")val cells = bindings["cells"] as MutableMap<String, Any?>val total = (cells["goods_total"] as String).toBigDecimal()cells["shipping_fee"] = if (total >= "150.00".toBigDecimal()) "0.00" else "12.90"
orders-2025-12.csv
order_no;order_date;customer;goods_total
CMD-2401;2025-12-03;Durand;89.00
CMD-2402;2025-12-09;Morel;172.50
CMD-2403;2025-12-15;Nguyen;240.00
CMD-2404;2025-12-22;Faure;150.00
manifests/shipping-fee-v2.kts
// Operator-provided: the shipping fee of an order. Free shipping from 200.00 of goods (from 1 January).@Suppress("UNCHECKED_CAST")val cells = bindings["cells"] as MutableMap<String, Any?>val total = (cells["goods_total"] as String).toBigDecimal()cells["shipping_fee"] = if (total >= "200.00".toBigDecimal()) "0.00" else "12.90"
orders-2026-01.csv
order_no;order_date;customer;goods_total
CMD-2501;2026-01-05;Roux;172.50
CMD-2502;2026-01-12;Garnier;199.99
CMD-2503;2026-01-19;Durand;215.00
manifests/20-shipped-order.yaml
kind: Entityname: shipped_order_blabel: Commande expédiéedescription: "An order with the shipping fee the operator's rule computed, and the run that wrote it."match: [order_no]scopes: [sales-b]columns:  order_no: { label: "Commande" }  order_date: { label: "Date" }  customer: { label: "Client" }  goods_total: { label: "Marchandises" }  shipping_fee: { label: "Port" }  run_id: { label: "Run" }sources:  - table: t_scenario_shipping_b    map: { order_no: order_no, order_date: order_date, customer: customer, goods_total: goods_total,           shipping_fee: shipping_fee, _run_id: run_id }   # _run_id: the run that wrote the row

Limits

  • The run lists the versions it applied, not which rows went through which. A script replaced during a run leaves its rows under both versions.
  • A fingerprint identifies a text. Keeping the script's versions stays the operator's job.
  • Synthetic orders.

Sales · audit

Shipping follows the operator's rule.

It changes on 1 January.

Free from 150.00, then from 200.00

The question

Why this fee, on this order?

  • 172.50 in December: free.
  • 172.50 in January: paid.

What is not changed

The connector stays the same.

  • It names the rule, it does not hold it.
  • The operator replaces the file.

The trap

A replaced rule leaves no trace.

  • Same file name.
  • Nobody knows which one ran.

What had to be written

_run_id: run_id

One line.

  • Each order names its run.
  • Each run names its version of the rule.
  • A 34-line scenario, two manifests.

The answer

Two runs, two fingerprints.

  • December: version 1.
  • January: version 2.

The limit

A fingerprint names a text.

  • Keeping the script's versions stays the operator's job.

Try it

The scenario replays locally.

Every step is published with its output.

This scenario runs on lumnik Open, free and open source.

Try lumnik Open →