Every carrier that has run ceded reinsurance for long enough has had the meeting. The claims director's large-loss report shows one net incurred on a hurricane claim. Finance's quarter-end pack shows another. The underwriting committee's view of the property book, net of the cat programme, shows a third. Each was built from a reasonable reading of the treaty, by a reasonable person, at a different time.
The fix is not a better reconciliation. It is a rule about ownership: one system derives net, and the others read it. In the Insight suite that system is InsightCede, and the rule is written into its README as a sentence rather than a preference.
InsightCede never writes back into UW or CW. Net premium, net incurred and ceded loss ratio are derived here and published as a read. The moment two systems both claim to own “net”, they disagree.
Why net cannot live in underwriting or claims
A cession is triggered by a policy transaction or a claim transaction. Put the engine inside underwriting and claims cannot cede; put it inside claims and policy cessions have no home. The organising dimension is different too: the workbenches think in policy years and accident years, the ceded side in treaty years and accounting periods. The counterparty is a reinsurer with its own credit risk, not an insured. And the consumers are Schedule F, the capital model and reinsurer billing, owned by the CFO and CRO rather than the chief underwriting officer or the head of claims.
So the two workbenches report what happened, and Cede decides what it means.
sequenceDiagram
participant CW as InsightCW
participant UW as InsightUW
participant C as InsightCede
participant P as InsightPulse
CW->>C: claim.payment_issued (outbox, same transaction as the cheque)
UW->>C: policy.bound / endorsed (outbox, same transaction)
Note over C: intake is idempotent on event_id. The engine cedes, raises recoverables and explains
CW->>C: read cede.claim_net for one claim
C-->>CW: gross, ceded paid and outstanding, recoverable, net
UW->>C: read cede.net_position
C-->>UW: programme totals and one row per treaty year
P->>C: read cede.net_position and cede.recoverable_aging
C-->>P: the same sums, aged by reinsurer
Note over CW,P: nothing flows back as a write
What goes in, and the two details that matter
The workbenches send events: policy.bound, policy.endorsed and
policy.audited from underwriting; claim.reserve_movement and
claim.payment_issued from claims. Each is written to an outbox in the same
transaction as the business change, so if the cheque committed, the event exists. A publisher
ships it afterwards and retries freely, because intake is idempotent on the event id.
Two payload rules carry more weight than they look. Premium is a delta, not a balance: a bind cedes the whole premium, an endorsement cedes only what it added, and sending a balance would re-cede the policy on every change. Loss is a position, not an increment: a claim event carries the ground-up incurred and paid after the movement, because an excess layer attaches on the size of the whole loss. The engine works out the movement itself, which is also why the same reserve sent twice cedes once.

What comes out: three contracts
Net leaves Cede through insight-dataapi: named contracts, reviewed like code, served over HTTP to any caller with a Cede token or API key. Every call runs in a read-only transaction with a statement timeout, through a guard that refuses identity, secret, connection and audit tables whatever the SQL says, and is itself recorded.
| Contract | Parameter | One row per | Read by | Row cap |
|---|---|---|---|---|
cede.net_position | none | the programme, each treaty year, and facultative | UW's reinsurance tab; Pulse's Reinsurance 360 | 500 |
cede.claim_net | claim_number (optional) | claim, largest gross incurred first | CW's reserve worksheet | 2,000 |
cede.recoverable_aging | reinsurer_code (optional) | reinsurer, largest outstanding first | Pulse's Reinsurance 360 | 500 |
The programme row of cede.net_position is the same sum as Cede's own
/position route, and a test asserts it: the contract's row, run through the same
measure definitions, must equal the route's answer on the same ledger. A change to one without
the other fails the build. The two derived columns are defined once: net cost of reinsurance
is ceded premium, less ceding commission, plus reinstatement premium; ceded loss ratio is
ceded loss over ceded premium.
Those are the demo programme's figures from the live position read — a demo US property-casualty carrier, not a customer. The net cost checks by hand: $14,168,774.93 of ceded premium, less $507,038.60 of commission, plus $724,929.26 of reinstatement premium.

net_position gets that figure as uncovered_retained, not a net that quietly assumes the cover was there.One flow, end to end
| Use case details | A claim's net on the reserve worksheet |
|---|---|
| Trigger | An adjuster opens a claim's reserve worksheet in InsightCW |
| Actor(s) | The adjuster or claims finance; InsightCW calling Cede as a client |
| Agent | None. This is a governed read, not an agent's work |
| Grounded in | cede.claim_net: Cede's register of the claim, the loss cessions and the recoverables |
| Prepares | Gross incurred, ceded outstanding and paid, the treaties that responded, recoverable outstanding, net incurred, net paid |
| Checkpoint & default level | None; a read changes nothing |
| What a person decides | The reserve. The net is information for it, not an input CW stores |
| What is recorded | The call, in Cede's dataapi_call: who asked, which contract, how long it took |
Nothing in that example required the three products to agree on a formula. They stopped computing net at all. The worksheet's sentence is generated from the read — “$23,435,097 of $28,435,097 incurred is ceded across 1 treaty; … net incurred $5,000,000” — and when Cede has nothing on a claim it says so in words (“Nothing ceded on this claim”) rather than showing a zero as if it were a fact.
Why a read and not a copy
The tempting alternative is a nightly copy: push Cede's figures into each product's own tables and let them query locally. It fails in three quiet ways. The copy is stale by design, so the claims worksheet disagrees with Cede for up to a day after every payment. The copy has to be re-derived when the engine writes a contra row, which is exactly when a hand-written query is most likely to be wrong. And the copy brings its own column types.
The last one is not hypothetical. The ledger's first home was MySQL, where the ORM's
floating-point type mapped to single precision, about seven significant digits: a
$28,435,097 loss was stored as 28,435,100. The engine now computes in Decimal
and stores Numeric(18, 2), and converts to a number only at the API boundary.
A consumer that reads the contract gets those figures as they were computed. A consumer that
keeps its own copy gets whatever its own schema does to them.
The clients are deliberately small. Each product discovers the contract keys from Cede's catalogue by their last segment, caches the catalogue for five minutes, sends a platform API key as a bearer and never logs it, and can be switched off with one environment flag.
What a consumer does when Cede does not answer
Each product's client turns every failure into a one-line reason a page can show: not configured, unreachable, refused, or the contract not published yet. Claims shows the reason and notes that events still go to Cede through the outbox. Underwriting falls back to its own local reinsurance rows and labels them as local. Pulse keeps the figures it had and records that Cede was unreachable as the data source. None of them invents a net to fill the gap.

What it does not do
- No point-in-time read. The contracts are live: they answer as the ledger stands
now. There is no
as_ofparameter, so “what was net at 30 September” is answered by the period's struck bordereaux or an export taken at the time, not by asking the contract. - Everyone signed in sees the whole programme. All three contracts are public to any Cede caller and no tenancy column is applied to the rows. Narrowing one means adding roles to the contract, which nobody has needed yet.
- Not every consumer is fully on it. Pulse's Reinsurance 360 reads its ceded figures and ageing from Cede, but its panel, large-loss list and narrative are still sample data until Cede publishes them, and the page says so block by block.
- Net is not stored on the policy or the claim. That is the point, and it has a cost: a report that joins underwriting data to net has to call Cede, or read an export, rather than run one query in one database.