From e54890e38a31243c97459ebd1080e7b9156b54f6 Mon Sep 17 00:00:00 2001 From: sglauser <20700029+sierragolflima@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:09:01 +0100 Subject: [PATCH 01/14] Changes to FutuRe (plot reactivity, formatting, icons) --- .../Memex.Portal.Shared/MemexConfiguration.cs | 13 +- .../AME-AGRICULTURE-AGRI.json | 2 +- .../AME-COMMERCIAL-CAS.json | 2 +- .../AME-COMMERCIAL-MARINE.json | 2 +- .../AME-COMMERCIAL-PROP.json | 2 +- .../AME-CYBER_TECH-CYBER.json | 2 +- .../AME-CYBER_TECH-PROF.json | 2 +- .../AME-ENERGY_MINING-ENRG.json | 2 +- .../AME-ENERGY_MINING-PROP.json | 2 +- .../AME-HOMEOWNERS-CAS.json | 2 +- .../AME-HOMEOWNERS-PROP.json | 2 +- .../TransactionMapping/AME-LIFE_ANN-LH.json | 2 +- .../AME-SPECIALTY_AVTN_US-AVTN.json | 2 +- .../AME-SPECIALTY_AVTN_US-SPEC.json | 2 +- .../AME-WORKERS_COMP-CAS.json | 2 +- .../EUR-COMM_FIRE-ENRG.json | 2 +- .../EUR-COMM_FIRE-PROP.json | 2 +- .../TransactionMapping/EUR-HOUSEHOLD-CAS.json | 2 +- .../EUR-HOUSEHOLD-PROP.json | 2 +- .../TransactionMapping/EUR-LIABILITY-CAS.json | 2 +- .../EUR-LIABILITY-PROF.json | 2 +- .../EUR-LIFE_HEALTH_EU-LH.json | 2 +- .../TransactionMapping/EUR-MOTOR-CAS.json | 19 +- .../EUR-SPECIALTY_AVTN-AVTN.json | 2 +- .../EUR-SPECIALTY_AVTN-SPEC.json | 2 +- .../EUR-TECH_RISK-CYBER.json | 2 +- .../EUR-TECH_RISK-PROF.json | 2 +- .../EUR-TRANSPORT-MARINE.json | 2 +- .../GroupAnalysis/_Source/FutuReDataLoader.cs | 172 +++++++----- .../_Source/ProfitabilityLayoutAreas.cs | 2 +- .../_Source/LocalAnalysisConfig.cs | 15 +- .../_Source/TransactionMapping.cs | 4 +- samples/Graph/Data/FutuRe/index.md | 30 +- .../AmericasIns/LineOfBusiness/icon.svg | 9 +- .../Graph/content/FutuRe/AmericasIns/icon.svg | 9 +- .../FutuRe/AsiaRe/LineOfBusiness/icon.svg | 9 +- samples/Graph/content/FutuRe/AsiaRe/icon.svg | 9 +- .../FutuRe/EuropeRe/LineOfBusiness/icon.svg | 9 +- .../Graph/content/FutuRe/EuropeRe/icon.svg | 9 +- .../content/FutuRe/LineOfBusiness/icon.svg | 9 +- .../RadzenChartView.razor | 3 +- .../Components/FormComponentBase.cs | 15 +- src/MeshWeaver.Data/DataContext.cs | 7 +- .../FutuReAnalysisTest.cs | 264 +++++++++--------- .../FxConversionTest.cs | 14 +- 45 files changed, 352 insertions(+), 321 deletions(-) diff --git a/memex/Memex.Portal.Shared/MemexConfiguration.cs b/memex/Memex.Portal.Shared/MemexConfiguration.cs index b5ac2627e..458173d06 100644 --- a/memex/Memex.Portal.Shared/MemexConfiguration.cs +++ b/memex/Memex.Portal.Shared/MemexConfiguration.cs @@ -306,10 +306,15 @@ public TBuilder ConfigureMemexMesh(IConfiguration configuration, bool isDevelopm // Each hub gets its own "content" collection pointing to a subdirectory .ConfigureDefaultNodeHub(config => { + // Declared before the if-block so it's available for both the "content" + // collection mapping below and the "attachments" mapping further down. + var nodePath = config.Address.ToString(); + if (contentStorageConfig != null) { - var nodePath = config.Address.ToString(); - var contentSubdir = nodePath; + // Scope static media (SVG, PNG, JPG) to a per-node subdirectory + // so each hub serves only its own content files. + var contentSubdir = $"content/{nodePath}"; // Combine with original BasePath for FileSystem; for AzureBlob, subdirectory is the blob prefix var basePath = string.IsNullOrEmpty(contentStorageConfig.BasePath) ? contentSubdir @@ -327,6 +332,10 @@ public TBuilder ConfigureMemexMesh(IConfiguration configuration, bool isDevelopm config = config.AddContentCollection(_ => nodeContentConfig); } + // Map "attachments" to "storage" with per-node subdirectory + // (needed by FutuRe and other samples that store datacube.csv, etc.) + config = config.MapContentCollection("attachments", "storage", $"attachments/{nodePath}"); + return config.AddDefaultLayoutAreas().AddThreadsLayoutArea().AddApiTokensSettingsTab(); }) // Add activity tracking to record user access patterns via ActivityLogBundler diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json index 166b32bc5..ea68af90c 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Agriculture", "groupLineOfBusiness": "AGRI", "groupLineOfBusinessName": "Agriculture", - "percentage": 1 + "percentage": 100 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json index 0defa2973..f20a2a80e 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Lines", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 0.25 + "percentage": 25 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json index 7746e6cf6..3c54abcf3 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Lines", "groupLineOfBusiness": "MARINE", "groupLineOfBusinessName": "Marine", - "percentage": 0.15 + "percentage": 15 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json index 8016a9226..3b0ce1f6e 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Lines", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 0.6 + "percentage": 60 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json index 1107a1b5f..fedc0fddf 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Cyber & Technology", "groupLineOfBusiness": "CYBER", "groupLineOfBusinessName": "Cyber", - "percentage": 0.7 + "percentage": 70 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json index 8d60c9bf8..4625ba4e0 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Cyber & Technology", "groupLineOfBusiness": "PROF", "groupLineOfBusinessName": "Professional Liability", - "percentage": 0.3 + "percentage": 30 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json index f12b2c1d8..79979c3a5 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Energy & Mining", "groupLineOfBusiness": "ENRG", "groupLineOfBusinessName": "Energy", - "percentage": 0.8 + "percentage": 80 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json index 71eb0eefb..a2e273ef4 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Energy & Mining", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 0.2 + "percentage": 20 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json index bb07c277f..e6da40438 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Homeowners", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 0.15 + "percentage": 15 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json index 53eb76e16..96cb7fdca 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Homeowners", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 0.85 + "percentage": 85 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json index 6a9041167..7be6b8578 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Life & Annuity", "groupLineOfBusiness": "LH", "groupLineOfBusinessName": "Life & Health", - "percentage": 1 + "percentage": 100 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json index 4ca304728..3fbfaedf1 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "AVTN", "groupLineOfBusinessName": "Aviation", - "percentage": 0.5 + "percentage": 50 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json index ff611a545..73cfff91a 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "SPEC", "groupLineOfBusinessName": "Specialty", - "percentage": 0.5 + "percentage": 50 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json index 7dcdf3226..f19927126 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Workers Compensation", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 1 + "percentage": 100 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json index cdd5e294d..9ce2c166f 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Fire", "groupLineOfBusiness": "ENRG", "groupLineOfBusinessName": "Energy", - "percentage": 0.2 + "percentage": 20 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json index cea7bd534..716d00abf 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Fire", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 0.8 + "percentage": 80 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json index 0c7ee7395..582574ff1 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Household", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 0.1 + "percentage": 10 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json index 87205bb0a..e771396fe 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Household", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 0.9 + "percentage": 90 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json index cf764f6a7..9ba95597f 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Liability", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 0.7 + "percentage": 70 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json index a8459f8a0..1e1d51a13 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Liability", "groupLineOfBusiness": "PROF", "groupLineOfBusinessName": "Professional Liability", - "percentage": 0.3 + "percentage": 30 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json index 5d5cbfbeb..673227e7c 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Life & Health", "groupLineOfBusiness": "LH", "groupLineOfBusinessName": "Life & Health", - "percentage": 1 + "percentage": 100 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json index faac77d1b..130d6cbe5 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json @@ -1,18 +1 @@ -{ - "id": "EUR-MOTOR-CAS", - "namespace": "FutuRe/EuropeRe/TransactionMapping", - "name": "EuropeRe: Motor → Casualty (100%)", - "nodeType": "FutuRe/TransactionMapping", - "isPersistent": true, - "content": { - "$type": "TransactionMapping", - "id": "EUR-MOTOR-CAS", - "businessUnit": "EuropeRe", - "localLineOfBusiness": "MOTOR", - "localLineOfBusinessName": "Motor", - "groupLineOfBusiness": "CAS", - "groupLineOfBusinessName": "Casualty", - "percentage": 1 - }, - "icon": "/static/storage/content/FutuRe/icon.svg" -} +{"$type":"MeshNode","id":"EUR-MOTOR-CAS","namespace":"FutuRe/EuropeRe/TransactionMapping","path":"FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS","mainNode":"FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS","name":"EuropeRe: Motor \u2192 Casualty (100%)","nodeType":"FutuRe/TransactionMapping","icon":"/static/storage/content/FutuRe/icon.svg","lastModified":"2026-03-17T12:52:05.829887+00:00","version":547,"state":"Active","content":{"$type":"TransactionMapping","id":"EUR-MOTOR-CAS","businessUnit":"EuropeRe","localLineOfBusiness":"MOTOR","localLineOfBusinessName":"Motor","groupLineOfBusiness":"CAS","groupLineOfBusinessName":"Casualty","percentage":100}} \ No newline at end of file diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json index 235bcdd83..9eab95e60 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "AVTN", "groupLineOfBusinessName": "Aviation", - "percentage": 0.3 + "percentage": 30 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json index bc659cc7f..c5c635382 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "SPEC", "groupLineOfBusinessName": "Specialty", - "percentage": 0.7 + "percentage": 70 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json index a6dc48994..ba2cb36a1 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Technology Risk", "groupLineOfBusiness": "CYBER", "groupLineOfBusinessName": "Cyber", - "percentage": 0.6 + "percentage": 60 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json index 42bd60410..b59c1d09e 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Technology Risk", "groupLineOfBusiness": "PROF", "groupLineOfBusinessName": "Professional Liability", - "percentage": 0.4 + "percentage": 40 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json index f710a794e..bafdd3cb5 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Transport", "groupLineOfBusiness": "MARINE", "groupLineOfBusinessName": "Marine", - "percentage": 1 + "percentage": 100 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs index 5845e2b7d..aa095d8f2 100644 --- a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs +++ b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs @@ -3,6 +3,7 @@ // DisplayName: FutuRe Data Loader // +using System.Collections.Immutable; using System.Globalization; using System.IO; using System.Reactive.Linq; @@ -50,7 +51,17 @@ public static IObservable> LoadLocalDataCube(IWorksp && val.ValueKind == JsonValueKind.String) buCurrency = val.GetString() ?? "CHF"; - var stream = await contentService.GetContentAsync("attachments", "datacube.csv", ct); + // GetContentAsync throws if the "attachments" collection isn't configured; + // treat that the same as a missing file — return an empty data cube. + Stream? stream; + try + { + stream = await contentService.GetContentAsync("attachments", "datacube.csv", ct); + } + catch + { + stream = null; + } if (stream == null) return (new List(), buCurrency); using var reader = new StreamReader(stream); @@ -183,9 +194,10 @@ public static IEnumerable AggregateToGroupLevel( LineOfBusinessName = lobLookup.GetValueOrDefault( rule.GroupLineOfBusiness, rule.GroupLineOfBusiness), Currency = currency, - Estimate = row.Estimate * rule.Percentage * estimateFxRate, + // Percentages are stored as whole numbers (e.g. 80 = 80%); divide by 100. + Estimate = row.Estimate * (rule.Percentage / 100.0) * estimateFxRate, Actual = row.Actual.HasValue - ? row.Actual.Value * rule.Percentage * actualFxRate + ? row.Actual.Value * (rule.Percentage / 100.0) * actualFxRate : null }); }); @@ -230,15 +242,15 @@ public static IObservable> LoadLocalLinesOfBusiness( : segments[0]; var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( + // Use AccumulateChanges (not raw .Select) so incremental add/update/remove + // deltas are merged into the full collection instead of replacing it. + return AccumulateChanges( + meshQuery.ObserveQuery( MeshQueryRequest.FromQuery( - $"nodeType:FutuRe/LineOfBusiness namespace:{buNamespace}/LineOfBusiness state:Active")) - .Select(change => change.Items - .Select(ConvertToLineOfBusiness) - .Where(lob => lob != null) - .Cast() - .OrderBy(lob => lob.Order)); + $"nodeType:FutuRe/LineOfBusiness namespace:{buNamespace}/LineOfBusiness state:Active")), + ConvertToLineOfBusiness, + lob => lob.SystemName) + .Select(lobs => lobs.OrderBy(lob => lob.Order)); } // --------------------------------------------------------------- @@ -251,14 +263,12 @@ public static IObservable> LoadLocalLinesOfBusiness( public static IObservable> LoadAmountTypes(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/AmountType namespace:FutuRe/AmountType state:Active")) - .Select(change => change.Items - .Select(ConvertToAmountType) - .Where(a => a != null) - .Cast() - .OrderBy(a => a.Order)); + return AccumulateChanges( + meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/AmountType namespace:FutuRe/AmountType state:Active")), + ConvertToAmountType, + a => a.SystemName) + .Select(items => items.OrderBy(a => a.Order)); } /// @@ -267,14 +277,12 @@ public static IObservable> LoadAmountTypes(IWorkspace wo public static IObservable> LoadCurrencies(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/Currency namespace:FutuRe/Currency state:Active")) - .Select(change => change.Items - .Select(ConvertToCurrency) - .Where(c => c != null) - .Cast() - .OrderBy(c => c.Order)); + return AccumulateChanges( + meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/Currency namespace:FutuRe/Currency state:Active")), + ConvertToCurrency, + c => c.Id) + .Select(items => items.OrderBy(c => c.Order)); } /// @@ -283,14 +291,12 @@ public static IObservable> LoadCurrencies(IWorkspace works public static IObservable> LoadCountries(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/Country namespace:FutuRe/Country state:Active")) - .Select(change => change.Items - .Select(ConvertToCountry) - .Where(c => c != null) - .Cast() - .OrderBy(c => c.Order)); + return AccumulateChanges( + meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/Country namespace:FutuRe/Country state:Active")), + ConvertToCountry, + c => c.Id) + .Select(items => items.OrderBy(c => c.Order)); } /// @@ -300,13 +306,11 @@ public static IObservable> LoadTransactionMappin { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/TransactionMapping namespace:FutuRe scope:descendants")) - .Select(change => change.Items - .Select(ConvertToTransactionMapping) - .Where(m => m != null) - .Cast()); + return AccumulateChanges( + meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/TransactionMapping namespace:FutuRe scope:descendants")), + ConvertToTransactionMapping, + m => m.Id); } /// @@ -315,14 +319,12 @@ public static IObservable> LoadTransactionMappin public static IObservable> LoadExchangeRates(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/ExchangeRate namespace:FutuRe/ExchangeRate state:Active")) - .Select(change => change.Items - .Select(ConvertToExchangeRate) - .Where(fx => fx != null) - .Cast() - .OrderBy(fx => fx.Order)); + return AccumulateChanges( + meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/ExchangeRate namespace:FutuRe/ExchangeRate state:Active")), + ConvertToExchangeRate, + fx => fx.SystemName) + .Select(items => items.OrderBy(fx => fx.Order)); } /// @@ -331,13 +333,11 @@ public static IObservable> LoadExchangeRates(IWorkspac public static IObservable> LoadBusinessUnits(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/BusinessUnit namespace:FutuRe state:Active")) - .Select(change => change.Items - .Select(ConvertToBusinessUnit) - .Where(bu => bu != null) - .Cast()); + return AccumulateChanges( + meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/BusinessUnit namespace:FutuRe state:Active")), + ConvertToBusinessUnit, + bu => bu.Id); } /// @@ -347,14 +347,12 @@ public static IObservable> LoadLinesOfBusinessFromNo { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return meshQuery - .ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/LineOfBusiness namespace:FutuRe/LineOfBusiness state:Active")) - .Select(change => change.Items - .Select(ConvertToLineOfBusiness) - .Where(lob => lob != null) - .Cast() - .OrderBy(lob => lob.Order)); + return AccumulateChanges( + meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/LineOfBusiness namespace:FutuRe/LineOfBusiness state:Active")), + ConvertToLineOfBusiness, + lob => lob.SystemName) + .Select(lobs => lobs.OrderBy(lob => lob.Order)); } // --------------------------------------------------------------- @@ -508,4 +506,48 @@ private static bool GetBool(JsonElement json, string property) => json.TryGetProperty(property, out var val) && (val.ValueKind == JsonValueKind.True || val.ValueKind == JsonValueKind.False) && val.GetBoolean(); + + // --------------------------------------------------------------- + // Incremental Change Accumulation + // --------------------------------------------------------------- + + /// + /// Accumulates incremental ObserveQuery changes into a full collection. + /// Initial/Reset emissions replace the entire dictionary; Added/Updated/Removed + /// apply deltas on top of the current state. + /// This keeps charts reactive to single-field edits (e.g. a mapping percentage) + /// without losing the rest of the collection. + /// + private static IObservable> AccumulateChanges( + IObservable> source, + Func convert, + Func getKey) + where T : class + { + return source + .Scan( + ImmutableDictionary.Empty, + (current, change) => + { + if (change.ChangeType is QueryChangeType.Initial or QueryChangeType.Reset) + return change.Items + .Select(convert) + .Where(item => item != null) + .Cast() + .ToImmutableDictionary(getKey); + + var builder = current.ToBuilder(); + foreach (var node in change.Items) + { + var item = convert(node); + if (item == null) continue; + if (change.ChangeType == QueryChangeType.Removed) + builder.Remove(getKey(item)); + else // Added or Updated + builder[getKey(item)] = item; + } + return builder.ToImmutable(); + }) + .Select(dict => dict.Values.AsEnumerable()); + } } diff --git a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs index b3399b94d..2ba7920c9 100644 --- a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs +++ b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs @@ -622,7 +622,7 @@ private static string BuildWaterfallSvg( var tickValue = maxValue * i / 4; var y = marginTop + ScaleY(tickValue); sb.AppendLine($" "); - sb.AppendLine($" {tickValue:F0}"); + sb.AppendLine($" {tickValue:N0}"); } // Bars, labels, and connectors diff --git a/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs b/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs index 57a90541c..264a1a688 100644 --- a/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs +++ b/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs @@ -13,6 +13,9 @@ /// /// Configures a local business unit analysis hub: loads CSV data /// and enriches with local line of business display names. +/// Registers the same reference/mapping data sources used by group analysis +/// (exchange rates, business units, transaction mappings, lines of business) +/// so local views have access to all dimensions needed for profitability reporting. /// public static class LocalAnalysisConfig { @@ -22,7 +25,17 @@ public static MessageHubConfiguration ConfigureLocalAnalysis(this MessageHubConf .AddData(data => data .WithVirtualDataSource("ReferenceData", vs => vs .WithVirtualType( - workspace => FutuReDataLoader.LoadAmountTypes(workspace))) + workspace => FutuReDataLoader.LoadAmountTypes(workspace)) + .WithVirtualType( + workspace => FutuReDataLoader.LoadExchangeRates(workspace)) + .WithVirtualType( + workspace => FutuReDataLoader.LoadBusinessUnits(workspace))) + .WithVirtualDataSource("TransactionMapping", vs => vs + .WithVirtualType( + workspace => FutuReDataLoader.LoadTransactionMappingsFromNodes(workspace))) + .WithVirtualDataSource("LineOfBusiness", vs => vs + .WithVirtualType( + workspace => FutuReDataLoader.LoadLinesOfBusinessFromNodes(workspace))) .WithVirtualDataSource("LocalData", vs => vs .WithVirtualType( workspace => FutuReDataLoader.LoadLocalDataCube(workspace)))) diff --git a/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs b/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs index 3ad22a805..caca49016 100644 --- a/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs +++ b/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs @@ -53,9 +53,9 @@ public record TransactionMapping public string GroupLineOfBusinessName { get; init; } = string.Empty; /// - /// Fraction of local LoB amount allocated to this group LoB (0..1). + /// Fraction of local LoB amount allocated to this group LoB (0..100). /// [Display(Name = "Percentage")] - [DisplayFormat(DataFormatString = "{0:P0}")] + [DisplayFormat(DataFormatString = "{0:0}%")] public double Percentage { get; init; } } diff --git a/samples/Graph/Data/FutuRe/index.md b/samples/Graph/Data/FutuRe/index.md index d23730c57..eb59a53e4 100644 --- a/samples/Graph/Data/FutuRe/index.md +++ b/samples/Graph/Data/FutuRe/index.md @@ -88,9 +88,7 @@ FutuRe has three business units across three continents. Each one grew independe Each BU writes business in its own currency (EUR, USD, JPY), classifies products with its own taxonomy, and reports on its own schedule. The group CFO wants one consolidated view. Today, that means weeks of reconciliation. ---- - -# Step 1: Local Data Cubes +## Step 1: Local Data Cubes Instead of ripping out existing systems, each BU creates a **local data product** — a structured data cube with its own Lines of Business, its own currency, and its own Performance. @@ -154,9 +152,7 @@ Each cube is a self-contained data product. The BU owns it, controls its quality - [EuropeRe Analysis Hub](@FutuRe/EuropeRe/Analysis/AnnualReport) — 8 local LoBs, EUR - [AmericasIns Analysis Hub](@FutuRe/AmericasIns/Analysis/AnnualReport) — 8 local LoBs, USD ---- - -# Step 2: Combining into a Group View +## Step 2: Combining into a Group View To consolidate, we need two transformations — and both are applied **virtually at query time**, with zero data copying. @@ -219,11 +215,9 @@ EuropeRe calls it "Household." AmericasIns calls it "Homeowners." Both map to th Three currencies, two conversion modes (Plan rate vs. Actuals rate), plus the option to view original currency. A single toolbar dropdown switches the entire dashboard — no recalculation, no spreadsheet exports. -[Explore the FX Conversion story →](@FutuRe/FxConversion) - ---- +- [Explore the FX Conversion story →](@FutuRe/FxConversion) -# Step 3: Onboarding AsiaRe +## Step 3: Onboarding AsiaRe When FutuRe acquires AsiaRe, the new unit needs to map its local product lines to the group standard. Traditionally a multi-month spreadsheet exercise — here, a MeshWeaver agent reads an email discussion between actuaries, proposes structured mapping rules, and integrates AsiaRe into the group Performance. @@ -247,7 +241,7 @@ graph LR Onboarding drops from months to minutes. The resulting rules are versioned, auditable, and governed — not buried in a spreadsheet. -[See the AsiaRe onboarding thread →](@FutuRe/AsiaRe/TransactionMapping/MappingRules/_Thread/t1) +- [See the AsiaRe onboarding thread →](@FutuRe/AsiaRe/TransactionMapping/MappingRules/_Thread/t1) --- @@ -255,7 +249,7 @@ Onboarding drops from months to minutes. The resulting rules are versioned, audi The group profitability dashboard assembles data from all business units in real time. Switch currencies, drill into Lines of Business, compare Plan vs. Actuals — all from one view. -@("FutuRe/Analysis/AnnualReport") +- [Access the group profitability annual report dashboard →](@FutuRe/Analysis/AnnualReport) --- @@ -263,7 +257,7 @@ The group profitability dashboard assembles data from all business units in real No ETL pipelines. No nightly batch jobs. No stale copies. Each BU owns its data. The group view is assembled virtually through reactive stream composition. When EuropeRe updates a number, the group dashboard updates instantly. -[How virtual data distribution works →](@FutuRe/DataDistribution) +- [How virtual data distribution works →](@FutuRe/DataDistribution) --- @@ -271,8 +265,8 @@ No ETL pipelines. No nightly batch jobs. No stale copies. Each BU owns its data. Every mapping rule, every exchange rate, every data product comes with clear ownership, SLOs, and audit trails. -- [Group Lines of Business](@FutuRe/LineOfBusiness/Search) — the 10 standard categories with SLOs -- [Exchange Rates](@FutuRe/ExchangeRate) — 4 currency pairs with governance -- [EuropeRe Mapping Rules](@FutuRe/EuropeRe/TransactionMapping/MappingRules) — 13 split rules across 8 local LoBs -- [AmericasIns Mapping Rules](@FutuRe/AmericasIns/TransactionMapping/MappingRules) — 14 split rules across 8 local LoBs -- [Why Data Mesh?](@FutuRe/WhyDataMesh) — The principles behind this architecture +- [Group Lines of Business →](@FutuRe/LineOfBusiness/Search) — the 10 standard categories with SLOs +- [Exchange Rates →](@FutuRe/ExchangeRate) — 4 currency pairs with governance +- [EuropeRe Mapping Rules →](@FutuRe/EuropeRe/TransactionMapping/MappingRules) — 13 split rules across 8 local LoBs +- [AmericasIns Mapping Rules →](@FutuRe/AmericasIns/TransactionMapping/MappingRules) — 14 split rules across 8 local LoBs +- [Why Data Mesh? →](@FutuRe/WhyDataMesh) — The principles behind this architecture diff --git a/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg index ef82d4a2f..021b97c12 100644 --- a/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg @@ -3,11 +3,6 @@ - - - - US - - - + + US diff --git a/samples/Graph/content/FutuRe/AmericasIns/icon.svg b/samples/Graph/content/FutuRe/AmericasIns/icon.svg index 4f4b6e58e..332f22efd 100644 --- a/samples/Graph/content/FutuRe/AmericasIns/icon.svg +++ b/samples/Graph/content/FutuRe/AmericasIns/icon.svg @@ -10,11 +10,6 @@ - - - - US - - - + + US diff --git a/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg index 0c01f1c82..59d73f483 100644 --- a/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg @@ -3,11 +3,6 @@ - - - - ASIA - - - + + ASIA diff --git a/samples/Graph/content/FutuRe/AsiaRe/icon.svg b/samples/Graph/content/FutuRe/AsiaRe/icon.svg index 7dcef9e79..2889851db 100644 --- a/samples/Graph/content/FutuRe/AsiaRe/icon.svg +++ b/samples/Graph/content/FutuRe/AsiaRe/icon.svg @@ -10,11 +10,6 @@ - - - - ASIA - - - + + ASIA diff --git a/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg index 14c3070d7..d1b247d33 100644 --- a/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg @@ -3,11 +3,6 @@ - - - - EU - - - + + EU diff --git a/samples/Graph/content/FutuRe/EuropeRe/icon.svg b/samples/Graph/content/FutuRe/EuropeRe/icon.svg index fda570353..9059640e6 100644 --- a/samples/Graph/content/FutuRe/EuropeRe/icon.svg +++ b/samples/Graph/content/FutuRe/EuropeRe/icon.svg @@ -10,11 +10,6 @@ - - - - EU - - - + + EU diff --git a/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg index 909ff7ae8..0adbc29f9 100644 --- a/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg @@ -3,11 +3,6 @@ - - - - GROUP - - - + + GROUP diff --git a/src/MeshWeaver.Blazor.Radzen/RadzenChartView.razor b/src/MeshWeaver.Blazor.Radzen/RadzenChartView.razor index f65cfa612..444949f06 100644 --- a/src/MeshWeaver.Blazor.Radzen/RadzenChartView.razor +++ b/src/MeshWeaver.Blazor.Radzen/RadzenChartView.razor @@ -31,7 +31,8 @@ } - + @* Format Y-axis with thousands separators and no decimals for readability (e.g. 1,234,567 instead of 1234567.00) *@ + diff --git a/src/MeshWeaver.Blazor/Components/FormComponentBase.cs b/src/MeshWeaver.Blazor/Components/FormComponentBase.cs index 286874fea..bedbc9b7b 100644 --- a/src/MeshWeaver.Blazor/Components/FormComponentBase.cs +++ b/src/MeshWeaver.Blazor/Components/FormComponentBase.cs @@ -82,10 +82,12 @@ protected override void BindData() DataPointer = ViewModel.Data as JsonPointerReference; valueUpdateSubject = new(); + // No .Skip(1) — the first value change must propagate immediately + // so that editing a field (e.g. TransactionMapping percentage) triggers + // reactive updates on the first keystroke, not only from the second one. AddBinding(valueUpdateSubject .ThrottleImmediate(TimeSpan.FromMilliseconds(DebounceWindow)) .DistinctUntilChanged() - .Skip(1) .Subscribe(x => { if (DataPointer is not null) @@ -231,6 +233,17 @@ protected virtual void OnBlur() { if (Stream is null || ViewModel is not { IsBlurable: true }) return; + + // Flush any pending value that the debounce cooldown hasn't emitted yet. + // Without this, a user could edit a value and click away before the + // debounce timer fires, causing the change to be silently lost. + if (hasPendingLocalChanges && DataPointer is not null) + { + lastSyncedValue = currentLocalValue; + hasPendingLocalChanges = false; + UpdatePointer(ConvertToData(currentLocalValue!)!, DataPointer); + } + Stream.Hub.Post(new BlurEvent(Area, Stream.StreamId), o => o.WithTarget(Stream.Owner)); } } diff --git a/src/MeshWeaver.Data/DataContext.cs b/src/MeshWeaver.Data/DataContext.cs index 9baaef99b..b41648e32 100644 --- a/src/MeshWeaver.Data/DataContext.cs +++ b/src/MeshWeaver.Data/DataContext.cs @@ -239,7 +239,12 @@ internal void OpenInitializationGate() /// private void RegisterInitializationFailureHandler(Exception initException) { - var errorMessage = $"Hub '{Hub.Address}' initialization failed: {initException.Message}"; + // Unwrap inner exceptions to surface the actual root cause in the error message. + // Without this, AggregateException wrapping produces doubled "Hub X failed: Hub X failed" messages. + var innerMessages = initException.InnerException is AggregateException agg + ? string.Join("; ", agg.InnerExceptions.Select(e => e.Message)) + : initException.InnerException?.Message ?? initException.Message; + var errorMessage = $"Hub '{Hub.Address}' initialization failed: {innerMessages}"; Hub.Register(delivery => { if (delivery.Message is DeliveryFailure) diff --git a/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs b/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs index 31280f7bf..8f382c2e3 100644 --- a/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs +++ b/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs @@ -543,6 +543,22 @@ await client.AwaitResponse( "Default area for Analysis hub should be 'LayoutAreas' (profitability catalog), not 'Overview'"); } + // ── Analysis Overview rendering (catches null stream / access control crashes) ── + + [Fact(Timeout = 20000)] + public async Task EuropeRe_Analysis_Overview_ShouldRender() + { + var control = await GetControlAsync("FutuRe/EuropeRe/Analysis", "Overview"); + control.Should().NotBeNull("EuropeRe Analysis Overview should render without crashing"); + } + + [Fact(Timeout = 20000)] + public async Task AmericasIns_Analysis_Overview_ShouldRender() + { + var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "Overview"); + control.Should().NotBeNull("AmericasIns Analysis Overview should render without crashing"); + } + // ── Local Analysis Hub (EuropeRe) ── [Fact(Timeout = 20000)] @@ -557,10 +573,11 @@ public async Task EuropeRe_KeyMetrics_ShouldHaveNonZeroData() [Fact(Timeout = 20000)] public async Task EuropeRe_KeyMetrics_ShouldShowCorrectCurrency() { + // With group-level aggregation enabled, the local hub converts to CHF (group currency) + // via the currency toolbar (default mode: Plan CHF). var control = await GetControlAsync("FutuRe/EuropeRe/Analysis", "KeyMetrics", unwrap: true); var md = AssertMarkdownWithNonZeroNumbers(control, "EuropeRe KeyMetrics currency"); - md.Should().Contain(" EUR", "EuropeRe amounts should be labeled with EUR, not CHF"); - md.Should().NotContain(" CHF", "EuropeRe should not show CHF — its currency is EUR"); + md.Should().Contain(" CHF", "EuropeRe local hub now aggregates to group level with default Plan CHF mode"); } [Fact(Timeout = 20000)] @@ -769,6 +786,122 @@ public async Task Group_AnnualProfitabilityWaterfall_ShouldRender() control.Should().BeOfType("AnnualProfitabilityWaterfall should return an HtmlControl with SVG"); } + [Fact(Timeout = 30000)] + public async Task Group_GroupProfitabilityDashboard_ShouldRender() + { + await InitializeChildAnalysisHubs(); + var control = await GetControlAsync("FutuRe/Analysis", "GroupProfitabilityDashboard", unwrap: false); + var stack = control.Should().BeOfType().Subject; + // Toolbar wraps content: top-level StackControl has [toolbar, content] + stack.Areas.Should().HaveCountGreaterThanOrEqualTo(2, + "GroupProfitabilityDashboard should contain toolbar and dashboard content"); + } + + [Fact(Timeout = 30000)] + public async Task Group_Analysis_DefaultArea_ShouldResolveToLayoutAreas() + { + await InitializeChildAnalysisHubs(); + var client = GetClient(); + var address = new Address("FutuRe/Analysis"); + + await client.AwaitResponse( + new PingRequest(), + o => o.WithTarget(address), + TestContext.Current.CancellationToken); + + var workspace = client.GetWorkspace(); + var reference = new LayoutAreaReference((string?)null); + + var stream = workspace.GetRemoteStream( + address, reference); + + var control = await stream + .GetControlStream("") + .Timeout(TimeSpan.FromSeconds(15)) + .FirstAsync(x => x is not null); + + var namedArea = control.Should().BeOfType().Subject; + namedArea.Area.Should().Be("LayoutAreas", + "Default area for group Analysis hub should be 'LayoutAreas' (profitability catalog)"); + } + + // ── Local Analysis Hub (AmericasIns) ── + + [Fact(Timeout = 20000)] + public async Task AmericasIns_KeyMetrics_ShouldHaveNonZeroData() + { + var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "KeyMetrics", unwrap: true); + var md = AssertMarkdownWithNonZeroNumbers(control, "AmericasIns KeyMetrics"); + md.Should().Contain("Total Premium", "KeyMetrics should show premium"); + md.Should().Contain("Loss Ratio", "KeyMetrics should show loss ratio"); + } + + [Fact(Timeout = 20000)] + public async Task AmericasIns_ProfitabilityTable_ShouldHaveNonZeroData() + { + var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "ProfitabilityTable", unwrap: true); + var md = AssertMarkdownWithNonZeroNumbers(control, "AmericasIns ProfitabilityTable"); + md.Should().Contain("Line of Business", "table should have headers"); + md.Should().Contain("Total", "table should have totals row"); + } + + [Fact(Timeout = 20000)] + public async Task AmericasIns_ProfitabilityOverview_ShouldRenderChart() + { + var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "ProfitabilityOverview", unwrap: true); + control.Should().BeOfType("ProfitabilityOverview should be a chart"); + } + + [Fact(Timeout = 20000)] + public async Task AmericasIns_AnnualProfitabilityWaterfall_ShouldRender() + { + var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "AnnualProfitabilityWaterfall", unwrap: true); + control.Should().BeOfType("AnnualProfitabilityWaterfall should return an HtmlControl with SVG"); + } + + [Fact(Timeout = 20000)] + public async Task AmericasIns_Analysis_DefaultArea_ShouldResolveToLayoutAreas() + { + var client = GetClient(); + var address = new Address("FutuRe/AmericasIns/Analysis"); + + await client.AwaitResponse( + new PingRequest(), + o => o.WithTarget(address), + TestContext.Current.CancellationToken); + + var workspace = client.GetWorkspace(); + var reference = new LayoutAreaReference((string?)null); + + var stream = workspace.GetRemoteStream( + address, reference); + + var control = await stream + .GetControlStream("") + .Timeout(TimeSpan.FromSeconds(15)) + .FirstAsync(x => x is not null); + + var namedArea = control.Should().BeOfType().Subject; + namedArea.Area.Should().Be("LayoutAreas", + "Default area for AmericasIns Analysis hub should be 'LayoutAreas' (profitability catalog)"); + } + + [Fact(Timeout = 20000)] + public async Task AmericasIns_Analysis_LayoutAreas_ShouldRenderCatalog() + { + var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "LayoutAreas"); + control.Should().NotBeNull("LayoutAreas catalog should render for AmericasIns Analysis hub"); + + var stack = control.Should().BeOfType().Subject; + Output.WriteLine($"LayoutAreas catalog has {stack.Areas?.Count ?? 0} areas"); + + stack.Areas.Should().HaveCountGreaterThanOrEqualTo(2, + "Catalog should have at least one category header (H2) + one grid of layout area tiles"); + + control.Should().NotBeOfType( + "LayoutAreas should show a catalog of profitability views, not a search/overview"); + } + // ── Business Unit Layout Areas ── /// @@ -832,7 +965,6 @@ public async Task AllNodeTypes_ShouldExist() ids.Should().Contain("Currency"); ids.Should().Contain("Country"); ids.Should().Contain("ExchangeRate"); - ids.Should().Contain("Report"); } /// @@ -888,69 +1020,6 @@ await client.AwaitResponse( "AnnualReport Overview should render the report content"); } - // ── AnnualReport Diagnostic Tests ── - - /// - /// Diagnostic: verify that the AnnualReport Overview contains @@() layout area references - /// in its markdown content, and that the Markdig pipeline converts them to layout-area divs. - /// - [Fact(Timeout = 30000)] - public async Task AnnualReport_Overview_ShouldContainLayoutAreaReferences() - { - var client = GetClient(); - var address = new Address("FutuRe/Analysis/AnnualReport"); - - await client.AwaitResponse(new PingRequest(), o => o.WithTarget(address), - TestContext.Current.CancellationToken); - - var workspace = client.GetWorkspace(); - var reference = new LayoutAreaReference("Overview"); - var stream = workspace.GetRemoteStream(address, reference); - - // Get the Overview control (StackControl with title + MarkdownControl + children) - var control = await stream.GetControlStream(reference.Area!) - .Timeout(TimeSpan.FromSeconds(15)) - .FirstAsync(x => x is not null); - - var stack = control.Should().BeOfType().Subject; - Output.WriteLine($"Stack has {stack.Areas?.Count} areas"); - - // Iterate through child areas to find the MarkdownControl - var foundMarkdown = false; - foreach (var area in stack.Areas ?? []) - { - var childKey = area.Area?.ToString(); - if (string.IsNullOrEmpty(childKey)) continue; - - var childControl = await stream.GetControlStream(childKey) - .Timeout(TimeSpan.FromSeconds(10)) - .FirstAsync(x => x is not null); - - Output.WriteLine($" Area '{childKey}': {childControl?.GetType().Name}"); - - if (childControl is MarkdownControl md) - { - foundMarkdown = true; - var markdown = md.Markdown?.ToString() ?? ""; - Output.WriteLine($" Markdown length: {markdown.Length}"); - Output.WriteLine($" Contains @@: {markdown.Contains("@@")}"); - Output.WriteLine($" First 500 chars: {markdown[..Math.Min(500, markdown.Length)]}"); - - markdown.Should().Contain("@@(", "Report markdown should contain @@() layout area references"); - - // Process through Markdig to verify HTML output - var pipeline = MeshWeaver.Markdown.MarkdownExtensions.CreateMarkdownPipeline(null); - var html = Markdig.Markdown.ToHtml(markdown, pipeline); - Output.WriteLine($" HTML contains layout-area: {html.Contains("layout-area")}"); - Output.WriteLine($" HTML snippet: {html[..Math.Min(500, html.Length)]}"); - - html.Should().Contain("layout-area", "Markdig should convert @@() to layout-area divs"); - } - } - - foundMarkdown.Should().BeTrue("Overview stack should contain a MarkdownControl with report body"); - } - /// /// Diagnostic: verify that IPathResolver resolves FutuRe/Analysis/X paths correctly, /// splitting into Prefix="FutuRe/Analysis" and Remainder="X". @@ -997,69 +1066,6 @@ public async Task AnnualReport_EmbeddedCharts_ShouldRenderViaPathResolution() control.Should().NotBeNull("KeyMetrics should render when accessed via path resolution"); } - // ── EuropeRe AnnualReport ── - - /// - /// Verifies that the EuropeRe AnnualReport Overview contains @@() layout area references - /// in its markdown content, and that Markdig converts them to layout-area divs. - /// Since EuropeRe charts render individually, this report should work end-to-end. - /// - [Fact(Timeout = 30000)] - public async Task EuropeRe_AnnualReport_Overview_ShouldContainLayoutAreaReferences() - { - var client = GetClient(); - var address = new Address("FutuRe/EuropeRe/Analysis/AnnualReport"); - - await client.AwaitResponse(new PingRequest(), o => o.WithTarget(address), - TestContext.Current.CancellationToken); - - var workspace = client.GetWorkspace(); - var reference = new LayoutAreaReference("Overview"); - var stream = workspace.GetRemoteStream(address, reference); - - var control = await stream.GetControlStream(reference.Area!) - .Timeout(TimeSpan.FromSeconds(15)) - .FirstAsync(x => x is not null); - - var stack = control.Should().BeOfType().Subject; - Output.WriteLine($"Stack has {stack.Areas?.Count} areas"); - - var foundMarkdown = false; - foreach (var area in stack.Areas ?? []) - { - var childKey = area.Area?.ToString(); - if (string.IsNullOrEmpty(childKey)) continue; - - var childControl = await stream.GetControlStream(childKey) - .Timeout(TimeSpan.FromSeconds(10)) - .FirstAsync(x => x is not null); - - Output.WriteLine($" Area '{childKey}': {childControl?.GetType().Name}"); - - if (childControl is MarkdownControl md) - { - foundMarkdown = true; - var markdown = md.Markdown?.ToString() ?? ""; - Output.WriteLine($" Markdown length: {markdown.Length}"); - Output.WriteLine($" Contains @@: {markdown.Contains("@@")}"); - Output.WriteLine($" First 500 chars: {markdown[..Math.Min(500, markdown.Length)]}"); - - markdown.Should().Contain("@@(", "EuropeRe report markdown should contain @@() layout area references"); - markdown.Should().Contain("FutuRe/EuropeRe/Analysis/KeyMetrics", - "Report should reference EuropeRe-specific chart paths"); - - var pipeline = MeshWeaver.Markdown.MarkdownExtensions.CreateMarkdownPipeline(null); - var html = Markdig.Markdown.ToHtml(markdown, pipeline); - Output.WriteLine($" HTML contains layout-area: {html.Contains("layout-area")}"); - Output.WriteLine($" HTML snippet: {html[..Math.Min(500, html.Length)]}"); - - html.Should().Contain("layout-area", "Markdig should convert @@() to layout-area divs"); - } - } - - foundMarkdown.Should().BeTrue("EuropeRe Overview stack should contain a MarkdownControl with report body"); - } - /// /// Verifies that IPathResolver resolves EuropeRe analysis chart paths correctly, /// splitting e.g. "FutuRe/EuropeRe/Analysis/KeyMetrics" into diff --git a/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs b/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs index 2de656430..37315948f 100644 --- a/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs +++ b/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs @@ -38,13 +38,13 @@ public class FxConversionTest { Id = "EUR-HOUSEHOLD-PROPERTY", BusinessUnit = "EuropeRe", LocalLineOfBusiness = "HOUSEHOLD", - GroupLineOfBusiness = "PROPERTY", Percentage = 1.0 + GroupLineOfBusiness = "PROPERTY", Percentage = 100 }, new() { Id = "AME-CASUALTY-CASUALTY", BusinessUnit = "AmericasIns", LocalLineOfBusiness = "CASUALTY", - GroupLineOfBusiness = "CASUALTY", Percentage = 1.0 + GroupLineOfBusiness = "CASUALTY", Percentage = 100 } ]; @@ -196,20 +196,20 @@ public void PartialPercentageMapping_SplitsRowCorrectly() } }; - // 2 mappings: HOUSEHOLD → PROPERTY at 60%, HOUSEHOLD → CASUALTY at 40% + // 2 mappings: HOUSEHOLD → PROPERTY at 60, HOUSEHOLD → CASUALTY at 40 var mappings = new[] { new TransactionMapping { Id = "EUR-HOUSEHOLD-PROPERTY", BusinessUnit = "EuropeRe", LocalLineOfBusiness = "HOUSEHOLD", GroupLineOfBusiness = "PROPERTY", - Percentage = 0.6 + Percentage = 60 }, new TransactionMapping { Id = "EUR-HOUSEHOLD-CASUALTY", BusinessUnit = "EuropeRe", LocalLineOfBusiness = "HOUSEHOLD", GroupLineOfBusiness = "CASUALTY", - Percentage = 0.4 + Percentage = 40 } }; @@ -278,7 +278,7 @@ public void MissingExchangeRate_FallsBackToOne() { Id = "ASIA-MARINE-MARINE", BusinessUnit = "AsiaRe", LocalLineOfBusiness = "MARINE", GroupLineOfBusiness = "MARINE", - Percentage = 1.0 + Percentage = 100 } }; @@ -410,7 +410,7 @@ public void ChfBusinessUnit_NoConversionApplied() { Id = "CHE-PROPERTY-PROPERTY", BusinessUnit = "SwissRe", LocalLineOfBusiness = "PROPERTY", GroupLineOfBusiness = "PROPERTY", - Percentage = 1.0 + Percentage = 100 } }; From 6d870f053c91315dbd7c747267f69aa6d152c292 Mon Sep 17 00:00:00 2001 From: sglauser <20700029+sierragolflima@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:27:55 +0200 Subject: [PATCH 02/14] Fix Microsoft login blank page on /signin-microsoft Exclude OAuth callback paths (signin-*) from Blazor catch-all route and OnboardingMiddleware so the OIDC handler processes them. Add OnRemoteFailure handler to surface auth errors as redirects instead of blank pages. Clean up redundant UseForwardedHeaders() call for production. Co-Authored-By: Claude Opus 4.6 --- .../Authentication/OnboardingMiddleware.cs | 1 + memex/Memex.Portal.Shared/MemexConfiguration.cs | 13 ++++++++----- .../AuthenticationBuilderExtensions.cs | 16 ++++++++++++++++ .../Infrastructure/NonfileRouteConstraint.cs | 3 ++- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/memex/Memex.Portal.Shared/Authentication/OnboardingMiddleware.cs b/memex/Memex.Portal.Shared/Authentication/OnboardingMiddleware.cs index 53f297011..01572a555 100644 --- a/memex/Memex.Portal.Shared/Authentication/OnboardingMiddleware.cs +++ b/memex/Memex.Portal.Shared/Authentication/OnboardingMiddleware.cs @@ -34,6 +34,7 @@ public class OnboardingMiddleware(RequestDelegate next, ILogger(options => { + options.ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedFor + | Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto + | Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedHost; options.KnownIPNetworks.Clear(); options.KnownProxies.Clear(); }); @@ -375,11 +378,11 @@ public static void StartMemexApplication(this WebApplication app) where TA // Forward headers from reverse proxy (Azure Container Apps) so OIDC // middleware constructs redirect URIs with the correct scheme and host. - app.UseForwardedHeaders(new ForwardedHeadersOptions - { - ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedFor - | Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto - }); + // When ASPNETCORE_FORWARDEDHEADERS_ENABLED=true (set in Bicep), the hosting + // layer calls UseForwardedHeaders() automatically from DI options. The explicit + // call here ensures it also works in local development without that env var. + if (!app.Environment.IsProduction()) + app.UseForwardedHeaders(); // Static files middleware must run before routing to serve _content/* paths from RCLs app.UseStaticFiles(); diff --git a/src/MeshWeaver.Blazor.Portal/Authentication/AuthenticationBuilderExtensions.cs b/src/MeshWeaver.Blazor.Portal/Authentication/AuthenticationBuilderExtensions.cs index 4496f2971..d1dd8aade 100644 --- a/src/MeshWeaver.Blazor.Portal/Authentication/AuthenticationBuilderExtensions.cs +++ b/src/MeshWeaver.Blazor.Portal/Authentication/AuthenticationBuilderExtensions.cs @@ -2,8 +2,10 @@ using System.Text.Json; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; namespace MeshWeaver.Blazor.Portal.Authentication; @@ -46,6 +48,20 @@ public static AuthenticationBuilder AddMicrosoftAuthentication( return issuer; throw new SecurityTokenInvalidIssuerException($"Invalid issuer: {issuer}"); }; + // Surface OIDC failures as a redirect instead of a blank page / 500 + options.Events = new OpenIdConnectEvents + { + OnRemoteFailure = context => + { + var logger = context.HttpContext.RequestServices + .GetRequiredService() + .CreateLogger("MicrosoftAuth"); + logger.LogError(context.Failure, "Microsoft OIDC remote failure"); + context.Response.Redirect("/login?error=auth_failed"); + context.HandleResponse(); + return Task.CompletedTask; + } + }; }); return builder; diff --git a/src/MeshWeaver.Blazor/Infrastructure/NonfileRouteConstraint.cs b/src/MeshWeaver.Blazor/Infrastructure/NonfileRouteConstraint.cs index f20a004ea..aa6fa040e 100644 --- a/src/MeshWeaver.Blazor/Infrastructure/NonfileRouteConstraint.cs +++ b/src/MeshWeaver.Blazor/Infrastructure/NonfileRouteConstraint.cs @@ -13,7 +13,8 @@ public class NonfileRouteConstraint : IRouteConstraint private static readonly HashSet ExcludedPrefixes = new(StringComparer.OrdinalIgnoreCase) { "_framework", "_content", "_blazor", "favicon.ico", - "auth", "dev", "mcp" + "auth", "dev", "mcp", + "signin-microsoft", "signin-google", "signin-linkedin", "signin-apple" }; public bool Match( From 3562654aef78be2cf12f029a2546c22e98f7a3f4 Mon Sep 17 00:00:00 2001 From: sglauser <20700029+sierragolflima@users.noreply.github.com> Date: Tue, 31 Mar 2026 01:28:44 +0200 Subject: [PATCH 03/14] updates to aspire deployment and project templates --- .gitignore | 5 +- .../appsettings.Development.json | 4 +- .../samples/Graph/Data/User/Admin.json | 13 + .../samples/Graph/Data/User/Alice.json | 13 + .../samples/Graph/Data/User/Bob.json | 13 + .../Graph/Data/User/_Access/Admin_Access.json | 17 ++ .../Graph/Data/User/_Access/Alice_Access.json | 17 ++ .../Graph/Data/User/_Access/Bob_Access.json | 17 ++ .../Memex.Portal.Shared/MemexConfiguration.cs | 8 +- memex/aspire/Memex.AppHost/Program.cs | 87 ++++-- memex/aspire/Memex.AppHost/azure.yaml | 7 + .../Memex.Database.Migration/Program.cs | 6 +- .../Memex.Portal.Distributed.csproj | 1 + .../Memex.Portal.Distributed/Program.cs | 18 ++ .../Data/Architecture.md | 13 +- .../Data/Architecture/Deployment.md | 254 +++++++++++++++--- .../Data/Architecture/ProjectTemplates.md | 246 +++++++++++++++++ .../Configuration/UserNodeType.cs | 5 +- .../PostgreSqlSchemaInitializer.cs | 21 ++ 19 files changed, 686 insertions(+), 79 deletions(-) create mode 100644 dist/templates/samples/Graph/Data/User/Admin.json create mode 100644 dist/templates/samples/Graph/Data/User/Alice.json create mode 100644 dist/templates/samples/Graph/Data/User/Bob.json create mode 100644 dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json create mode 100644 dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json create mode 100644 dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json create mode 100644 memex/aspire/Memex.AppHost/azure.yaml create mode 100644 src/MeshWeaver.Documentation/Data/Architecture/ProjectTemplates.md diff --git a/.gitignore b/.gitignore index 257d1f473..9c34c1060 100644 --- a/.gitignore +++ b/.gitignore @@ -376,7 +376,10 @@ samples/Graph/Data/VUser/ /memex/Azurite/Orleans/__azurite_db_table__.json /memex/Azurite/Orleans/AzuriteConfig /memex/Azurite/Data/__blobstorage__/e7429c6f-7085-4422-ae51-515f33ac8fc1 +/memex/Azurite/Data/__blobstorage__/901d58e2-347d-4ffb-b363-14b77f399fe7 # User activity data **/_useractivity/ -/memex/Azurite/Data/__blobstorage__/901d58e2-347d-4ffb-b363-14b77f399fe7 + +# Azure Developer CLI +.azure/ diff --git a/dist/templates/Memex.Portal.Monolith/appsettings.Development.json b/dist/templates/Memex.Portal.Monolith/appsettings.Development.json index 4fa59b6cb..c3f5d9758 100644 --- a/dist/templates/Memex.Portal.Monolith/appsettings.Development.json +++ b/dist/templates/Memex.Portal.Monolith/appsettings.Development.json @@ -14,12 +14,12 @@ "Graph": { "Storage": { "Type": "FileSystem", - "BasePath": "../../samples/Graph/Data" + "BasePath": "../samples/Graph/Data" } }, "Storage": { "Name": "storage", "SourceType": "FileSystem", - "BasePath": "../../samples/Graph" + "BasePath": "../samples/Graph" } } diff --git a/dist/templates/samples/Graph/Data/User/Admin.json b/dist/templates/samples/Graph/Data/User/Admin.json new file mode 100644 index 000000000..198b4aa02 --- /dev/null +++ b/dist/templates/samples/Graph/Data/User/Admin.json @@ -0,0 +1,13 @@ +{ + "id": "Admin", + "namespace": "User", + "name": "Admin", + "nodeType": "User", + "icon": "/static/NodeTypeIcons/person.svg", + "isPersistent": true, + "content": { + "$type": "User", + "email": "admin@example.com", + "bio": "Default administrator account." + } +} diff --git a/dist/templates/samples/Graph/Data/User/Alice.json b/dist/templates/samples/Graph/Data/User/Alice.json new file mode 100644 index 000000000..941459f5b --- /dev/null +++ b/dist/templates/samples/Graph/Data/User/Alice.json @@ -0,0 +1,13 @@ +{ + "id": "Alice", + "namespace": "User", + "name": "Alice Chen", + "nodeType": "User", + "icon": "/static/NodeTypeIcons/person.svg", + "isPersistent": true, + "content": { + "$type": "User", + "email": "alice.chen@meshweaver.io", + "bio": "Software engineer and project contributor." + } +} diff --git a/dist/templates/samples/Graph/Data/User/Bob.json b/dist/templates/samples/Graph/Data/User/Bob.json new file mode 100644 index 000000000..30b66de78 --- /dev/null +++ b/dist/templates/samples/Graph/Data/User/Bob.json @@ -0,0 +1,13 @@ +{ + "id": "Bob", + "namespace": "User", + "name": "Bob Smith", + "nodeType": "User", + "icon": "/static/NodeTypeIcons/person.svg", + "isPersistent": true, + "content": { + "$type": "User", + "email": "bob.smith@meshweaver.io", + "bio": "Software engineer and project contributor." + } +} diff --git a/dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json b/dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json new file mode 100644 index 000000000..15e5ad803 --- /dev/null +++ b/dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json @@ -0,0 +1,17 @@ +{ + "id": "Admin_Access", + "namespace": "User/_Access", + "name": "Admin Access", + "icon": "/static/NodeTypeIcons/shield.svg", + "nodeType": "AccessAssignment", + "content": { + "$type": "AccessAssignment", + "accessObject": "Admin", + "displayName": "Admin", + "roles": [ + { + "role": "Admin" + } + ] + } +} diff --git a/dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json b/dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json new file mode 100644 index 000000000..12d4cb655 --- /dev/null +++ b/dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json @@ -0,0 +1,17 @@ +{ + "id": "Alice_Access", + "namespace": "User/_Access", + "name": "Alice Access", + "icon": "/static/NodeTypeIcons/shield.svg", + "nodeType": "AccessAssignment", + "content": { + "$type": "AccessAssignment", + "accessObject": "Alice", + "displayName": "Alice Chen", + "roles": [ + { + "role": "Admin" + } + ] + } +} diff --git a/dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json b/dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json new file mode 100644 index 000000000..25443b23e --- /dev/null +++ b/dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json @@ -0,0 +1,17 @@ +{ + "id": "Bob_Access", + "namespace": "User/_Access", + "name": "Bob Access", + "icon": "/static/NodeTypeIcons/shield.svg", + "nodeType": "AccessAssignment", + "content": { + "$type": "AccessAssignment", + "accessObject": "Bob", + "displayName": "Bob Smith", + "roles": [ + { + "role": "Admin" + } + ] + } +} diff --git a/memex/Memex.Portal.Shared/MemexConfiguration.cs b/memex/Memex.Portal.Shared/MemexConfiguration.cs index cc09ed05e..66cdca6fb 100644 --- a/memex/Memex.Portal.Shared/MemexConfiguration.cs +++ b/memex/Memex.Portal.Shared/MemexConfiguration.cs @@ -378,11 +378,9 @@ public static void StartMemexApplication(this WebApplication app) where TA // Forward headers from reverse proxy (Azure Container Apps) so OIDC // middleware constructs redirect URIs with the correct scheme and host. - // When ASPNETCORE_FORWARDEDHEADERS_ENABLED=true (set in Bicep), the hosting - // layer calls UseForwardedHeaders() automatically from DI options. The explicit - // call here ensures it also works in local development without that env var. - if (!app.Environment.IsProduction()) - app.UseForwardedHeaders(); + // Always enabled: in production it reads X-Forwarded-* from the ACA proxy; + // in local dev it's a no-op since no proxy sets those headers. + app.UseForwardedHeaders(); // Static files middleware must run before routing to serve _content/* paths from RCLs app.UseStaticFiles(); diff --git a/memex/aspire/Memex.AppHost/Program.cs b/memex/aspire/Memex.AppHost/Program.cs index 4c1c24eee..e1c0862f1 100644 --- a/memex/aspire/Memex.AppHost/Program.cs +++ b/memex/aspire/Memex.AppHost/Program.cs @@ -22,17 +22,20 @@ // // Required user-secrets for distributed modes: // Parameters:azure-foundry-key -// Parameters:embedding-endpoint -// Parameters:embedding-key -// Parameters:embedding-model // Parameters:microsoft-client-id // Parameters:microsoft-client-secret // +// Optional user-secrets (features disabled when absent): +// Parameters:embedding-endpoint, embedding-key, embedding-model +// Parameters:google-client-id, google-client-secret +// Parameters:custom-domain, certificate-name +// // For local-test/local-prod, also set the connection string to the Azure PostgreSQL: // ConnectionStrings:memex (Azure PostgreSQL, bypassing provisioning) // Blob Storage uses RunAsExisting with Azure Identity (az login) — no secrets needed. -var mode = builder.Configuration["mode"]?.ToLowerInvariant() ?? "local"; +var mode = builder.Configuration["mode"]?.ToLowerInvariant() + ?? (builder.ExecutionContext.IsPublishMode ? "test" : "local"); if (mode == "monolith") { @@ -49,20 +52,29 @@ // LLM API key (single Azure Foundry key for both Anthropic and OpenAI endpoints) var azureFoundryKey = builder.AddParameter("azure-foundry-key", secret: true); -// Embedding configuration -var embeddingEndpoint = builder.AddParameter("embedding-endpoint", secret: false); -var embeddingKey = builder.AddParameter("embedding-key", secret: true); -var embeddingModel = builder.AddParameter("embedding-model", secret: false); +// Embedding — optional: skip if embedding-key is not configured +var hasEmbedding = !string.IsNullOrEmpty(builder.Configuration["Parameters:embedding-key"]); +var embeddingEndpoint = hasEmbedding ? builder.AddParameter("embedding-endpoint", secret: false) : null; +var embeddingKey = hasEmbedding ? builder.AddParameter("embedding-key", secret: true) : null; +var embeddingModel = hasEmbedding ? builder.AddParameter("embedding-model", secret: false) : null; -// Authentication +// Authentication — Microsoft (required) var microsoftClientId = builder.AddParameter("microsoft-client-id", secret: false); var microsoftClientSecret = builder.AddParameter("microsoft-client-secret", secret: true); -var googleClientId = builder.AddParameter("google-client-id", secret: false); -var googleClientSecret = builder.AddParameter("google-client-secret", secret: true); -// --- Custom domain (for deployed modes) --- -var customDomain = builder.AddParameter("custom-domain", secret: false); -var certificateName = builder.AddParameter("certificate-name", secret: false); +// Authentication — Microsoft tenant (optional: defaults to "common" for multi-tenant) +var hasTenantId = !string.IsNullOrEmpty(builder.Configuration["Parameters:microsoft-tenant-id"]); +var microsoftTenantId = hasTenantId ? builder.AddParameter("microsoft-tenant-id", secret: false) : null; + +// Authentication — Google (optional: skip if google-client-secret is not configured) +var hasGoogleAuth = !string.IsNullOrEmpty(builder.Configuration["Parameters:google-client-secret"]); +var googleClientId = hasGoogleAuth ? builder.AddParameter("google-client-id", secret: false) : null; +var googleClientSecret = hasGoogleAuth ? builder.AddParameter("google-client-secret", secret: true) : null; + +// --- Custom domain (optional, for deployed modes with DNS configured) --- +var hasCustomDomain = !string.IsNullOrEmpty(builder.Configuration["Parameters:custom-domain"]); +var customDomain = hasCustomDomain ? builder.AddParameter("custom-domain", secret: false) : null; +var certificateName = hasCustomDomain ? builder.AddParameter("certificate-name", secret: false) : null; // --- Infrastructure axes --- var isDeployed = mode is "test" or "prod"; @@ -118,8 +130,9 @@ var dbMigration = builder .AddProject("db-migration") .WithReference(appInsights) - .WaitFor(appInsights) - .WithEnvironment("Embedding__Model", embeddingModel); + .WaitFor(appInsights); +if (hasEmbedding) + dbMigration = dbMigration.WithEnvironment("Embedding__Model", embeddingModel!); // --- Portal (co-hosted Orleans silo + web) --- var portal = builder @@ -127,10 +140,6 @@ .WithExternalHttpEndpoints() .WithReference(orleans) .WithReference(appInsights) - // Embedding - .WithEnvironment("Embedding__Endpoint", embeddingEndpoint) - .WithEnvironment("Embedding__ApiKey", embeddingKey) - .WithEnvironment("Embedding__Model", embeddingModel) // LLM: Anthropic (Azure Foundry Claude) .WithEnvironment("Anthropic__Endpoint", "https://s-meshweaver.services.ai.azure.com/anthropic/") .WithEnvironment("Anthropic__ApiKey", azureFoundryKey) @@ -146,12 +155,11 @@ .WithEnvironment("AzureOpenAIS__ApiKey", azureFoundryKey) .WithEnvironment("AzureOpenAIS__Models__0", "gpt-5-mini") .WithEnvironment("AzureOpenAIS__Models__1", "gpt-5.4") - // Authentication + // Authentication — Microsoft (required) .WithEnvironment("Authentication__EnableDevLogin", mode != "prod" ? "true" : "false") .WithEnvironment("Authentication__Microsoft__ClientId", microsoftClientId) .WithEnvironment("Authentication__Microsoft__ClientSecret", microsoftClientSecret) - .WithEnvironment("Authentication__Google__ClientId", googleClientId) - .WithEnvironment("Authentication__Google__ClientSecret", googleClientSecret) + .WithEnvironment("Authentication__Microsoft__TenantId", "common") // Wait for dependencies .WaitFor(orleansTables) .WaitFor(grainStateBlobs) @@ -159,8 +167,15 @@ // ACA deployment: sticky sessions (Blazor Server) + custom domain + resources .PublishAsAzureContainerApp((module, app) => { + // Fix: Aspire's Orleans integration sets primary ingress to TCP/internal + // on the silo port. Override to HTTP/external for the Blazor web app. + app.Configuration.Ingress.External = true; + app.Configuration.Ingress.Transport = ContainerAppIngressTransportMethod.Auto; + app.Configuration.Ingress.TargetPort = 8080; + app.Configuration.Ingress.StickySessionsAffinity = StickySessionAffinity.Sticky; - app.ConfigureCustomDomain(customDomain, certificateName); + if (hasCustomDomain) + app.ConfigureCustomDomain(customDomain!, certificateName!); // Scale: min 2 replicas (Orleans needs ≥2 for resilience), max 6 under load. // Each replica: 2 vCPU / 4Gi (50% of Consumption tier max 4 vCPU / 8Gi). @@ -168,6 +183,30 @@ app.Template.Scale.MaxReplicas = 6; }); +// Embedding — optional +if (hasEmbedding) +{ + portal = portal + .WithEnvironment("Embedding__Endpoint", embeddingEndpoint!) + .WithEnvironment("Embedding__ApiKey", embeddingKey!) + .WithEnvironment("Embedding__Model", embeddingModel!); +} + +// Authentication — Google (optional) +if (hasGoogleAuth) +{ + portal = portal + .WithEnvironment("Authentication__Google__ClientId", googleClientId!) + .WithEnvironment("Authentication__Google__ClientSecret", googleClientSecret!); +} + +// Authentication — Microsoft tenant (optional: overrides "common" default) +if (hasTenantId) +{ + portal = portal + .WithEnvironment("Authentication__Microsoft__TenantId", microsoftTenantId!); +} + // --- Azure Blob Storage --- if (useLocalDb) { diff --git a/memex/aspire/Memex.AppHost/azure.yaml b/memex/aspire/Memex.AppHost/azure.yaml new file mode 100644 index 000000000..5a3c205b2 --- /dev/null +++ b/memex/aspire/Memex.AppHost/azure.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json +name: memex +services: + app: + language: dotnet + project: . + host: containerapp diff --git a/memex/aspire/Memex.Database.Migration/Program.cs b/memex/aspire/Memex.Database.Migration/Program.cs index 0ae7907a1..b63df020a 100644 --- a/memex/aspire/Memex.Database.Migration/Program.cs +++ b/memex/aspire/Memex.Database.Migration/Program.cs @@ -42,10 +42,12 @@ // (portal, migration) can create per-organization schemas at runtime. if (connectionString.Contains("database.azure.com")) { + var csb = new NpgsqlConnectionStringBuilder(connectionString); + var dbName = csb.Database ?? "memex"; await using var grantCmd = dataSource.CreateCommand( - "GRANT CREATE ON DATABASE memex TO azure_pg_admin"); + $"GRANT CREATE ON DATABASE \"{dbName}\" TO azure_pg_admin"); await grantCmd.ExecuteNonQueryAsync(); - logger.LogInformation("Granted CREATE ON DATABASE to azure_pg_admin."); + logger.LogInformation("Granted CREATE ON DATABASE {Database} to azure_pg_admin.", dbName); } // ═══════════════════════════════════════════════════════════════════════════ diff --git a/memex/aspire/Memex.Portal.Distributed/Memex.Portal.Distributed.csproj b/memex/aspire/Memex.Portal.Distributed/Memex.Portal.Distributed.csproj index 3d6ab9c9c..7c7786747 100644 --- a/memex/aspire/Memex.Portal.Distributed/Memex.Portal.Distributed.csproj +++ b/memex/aspire/Memex.Portal.Distributed/Memex.Portal.Distributed.csproj @@ -27,5 +27,6 @@ + diff --git a/memex/aspire/Memex.Portal.Distributed/Program.cs b/memex/aspire/Memex.Portal.Distributed/Program.cs index 3d3695cef..d72013d61 100644 --- a/memex/aspire/Memex.Portal.Distributed/Program.cs +++ b/memex/aspire/Memex.Portal.Distributed/Program.cs @@ -1,6 +1,8 @@ using Azure.Identity; +using Azure.Storage.Blobs; using Memex.Portal.ServiceDefaults; using Memex.Portal.Shared; +using Microsoft.AspNetCore.DataProtection; using MeshWeaver.Hosting.Orleans; using MeshWeaver.Hosting.PostgreSql; using MeshWeaver.Messaging; @@ -9,6 +11,7 @@ var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); +builder.Services.AddServerSideBlazor().AddCircuitOptions(o => o.DetailedErrors = true); // Log levels controlled via appsettings.Development.json @@ -17,6 +20,21 @@ builder.AddKeyedAzureBlobServiceClient("storage"); builder.AddKeyedAzureBlobServiceClient("orleans-grain-state"); +// Data protection: persist keys to Azure Blob Storage (shared across replicas) +var dpConfig = builder.Configuration.GetSection("DataProtection"); +var containerName = dpConfig["ContainerName"] ?? "dataprotection"; +var blobName = dpConfig["BlobName"] ?? "keys.xml"; + +builder.Services.AddDataProtection() + .SetApplicationName("MemexPortal") + .PersistKeysToAzureBlobStorage(sp => + { + var blobServiceClient = sp.GetRequiredKeyedService("storage"); + var containerClient = blobServiceClient.GetBlobContainerClient(containerName); + containerClient.CreateIfNotExists(); + return containerClient.GetBlobClient(blobName); + }); + // Register Aspire-injected PostgreSQL data source (with pgvector support) // Single shared pool for all partition queries (schema-qualified SQL). // Pool size must handle parallel fan-out across all schemas. diff --git a/src/MeshWeaver.Documentation/Data/Architecture.md b/src/MeshWeaver.Documentation/Data/Architecture.md index 2d5d0d359..90bfdda76 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture.md +++ b/src/MeshWeaver.Documentation/Data/Architecture.md @@ -107,7 +107,18 @@ Flexible security through `IDataValidator`: --- -## 7. Deployment +## 7. Project Templates + +Bootstrap a new MeshWeaver portal with a single command: +- `dotnet new meshweaver-memex -o MyProject` scaffolds a complete solution +- Monolith and distributed deployment modes included +- Sample data, dev login users, and access control pre-configured + +[Read more: Project Templates](ProjectTemplates) + +--- + +## 8. Deployment Deploy with **.NET Aspire** to Azure Container Apps: - Multiple modes: `local`, `local-test`, `local-prod`, `test`, `prod`, `monolith` diff --git a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md index fee8a43bf..ae5f63371 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md @@ -7,6 +7,71 @@ Icon: Cloud MeshWeaver uses **.NET Aspire** for orchestration and deployment. The Aspire AppHost (`memex/aspire/Memex.AppHost`) defines all infrastructure resources — PostgreSQL, Azure Blob Storage, Orleans clustering, Application Insights — and provisions them automatically via the Aspire CLI. +# Prerequisites + +## Aspire CLI + +Install the Aspire CLI as a global .NET tool: + +```bash +dotnet tool install -g aspire.cli +``` + +Verify installation: + +```bash +aspire --version +``` + +## Azure Login + +You must be logged into Azure before deploying: + +```bash +az login +azd auth login +``` + +## User Secrets + +All parameters must be configured via `dotnet user-secrets` before deploying. Without secrets, `aspire deploy` will prompt interactively for each missing parameter and fail in non-interactive environments (CI/CD, piped shells). + +Set secrets from the AppHost project directory: + +```bash +cd memex/aspire/Memex.AppHost +dotnet user-secrets set "Parameters:azure-foundry-key" "" +dotnet user-secrets set "Parameters:microsoft-client-id" "" +dotnet user-secrets set "Parameters:microsoft-client-secret" "" +``` + +Or from the repository root using `--project`: + +```bash +dotnet user-secrets set "Parameters:azure-foundry-key" "" --project memex/aspire/Memex.AppHost +``` + +The three secrets above are **required** — deployment fails without them. The following are **optional** (features are disabled when absent — the AppHost skips these parameters automatically): + +```bash +dotnet user-secrets set "Parameters:microsoft-tenant-id" "" +dotnet user-secrets set "Parameters:embedding-endpoint" "" +dotnet user-secrets set "Parameters:embedding-key" "" +dotnet user-secrets set "Parameters:embedding-model" "" +dotnet user-secrets set "Parameters:google-client-id" "" +dotnet user-secrets set "Parameters:google-client-secret" "" +dotnet user-secrets set "Parameters:custom-domain" "" +dotnet user-secrets set "Parameters:certificate-name" "" +``` + +> **Important:** For `microsoft-client-secret`, use the secret **value** (the string shown once when you create the secret), not the secret **ID** (the GUID). These are different fields in the Azure portal. + +Verify secrets are configured: + +```bash +dotnet user-secrets list --project memex/aspire/Memex.AppHost +``` + # Deployment Modes The AppHost supports multiple modes, passed as `--mode `: @@ -20,31 +85,68 @@ The AppHost supports multiple modes, passed as `--mode `: | `prod` | Azure (memex) | Azure (meshweavermemex) | Azure | memex-prod | | `monolith` | FileSystem (standalone) | — | — | memex-monolith | -# Deploying to Production +# Deploying to Azure + +All `aspire deploy` commands require `-e Development`. This tells Aspire to use the **ASP.NET Development environment**, which is what loads user secrets. Without it, Aspire defaults to the Production environment where user secrets are ignored, causing interactive prompts that fail in non-interactive terminals. The **deployment target** (test vs prod) is controlled separately by the `--mode` flag. -Deploy using the Aspire CLI: +## Deploy to Test ```bash -aspire deploy --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode prod +aspire deploy -e Development --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode test ``` -For test environment: +## Deploy to Production ```bash -aspire deploy --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode test +aspire deploy -e Development --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode prod ``` -The `aspire deploy` command builds the application, pushes container images, and provisions/updates Azure resources as defined in the AppHost. +## What `aspire deploy` Does + +1. **Builds** the AppHost project and resolves the Aspire application model +2. **Prompts for parameters** — reads from user-secrets; prompts interactively for any missing values +3. **Generates Bicep** infrastructure templates (stored in `memex/aspire/Memex.AppHost/infra/`) +4. **Provisions Azure resources** via ARM deployment (resource group, Container App Environment, PostgreSQL, Blob Storage, etc.) +5. **Builds container images** for each project (portal, db-migration) +6. **Pushes images** to the provisioned Azure Container Registry +7. **Deploys Container Apps** with the configured environment variables, scaling rules, and custom domain + +## Generated Infrastructure + +The first `aspire deploy` generates Bicep templates in `memex/aspire/Memex.AppHost/infra/`: + +``` +infra/ +├── main.bicep # Root deployment template +├── main.parameters.json # Parameter bindings (uses ${AZURE_*} env vars) +├── memex-aca/ # Container App Environment +├── memex-aca-acr/ # Container Registry +├── memex-test/ or memex-prod/ # Portal Container App +├── db-migration/ # Migration Container App (run-to-completion) +├── memex-postgres/ # PostgreSQL Flexible Server +├── memexblobs/ # Azure Storage Account +├── orleansstorage/ # Orleans Storage Account +├── appinsights/ # Application Insights +└── *-identity/, *-roles-*/ # Managed identities and role assignments +``` + +These templates are committed to the repo and reused on subsequent deploys. To regenerate them: + +```bash +aspire generate --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode test +``` # Running Locally -For local development with Docker containers: +## Local Development (Docker) ```bash aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj ``` -This starts in `local` mode by default, using Docker pgvector and emulated Azure services. +This starts in `local` mode by default, using Docker pgvector and emulated Azure services (Azurite). + +## Local with Azure Databases To run locally against Azure test or prod databases: @@ -53,7 +155,9 @@ aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode l aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode local-prod ``` -These modes connect to Azure PostgreSQL and Blob Storage while keeping Orleans emulated locally. +These modes connect to Azure PostgreSQL and Blob Storage while keeping Orleans emulated locally. Requires: +- `ConnectionStrings:memex` user secret (PostgreSQL connection string) +- Active `az login` session (for Blob Storage via Azure Identity) # Monolith Mode @@ -73,7 +177,10 @@ aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode m ## Azure Container Apps -Deployed modes (`test`, `prod`) run on **Azure Container Apps** in Sweden Central with sticky sessions enabled for Blazor Server. +Deployed modes (`test`, `prod`) run on **Azure Container Apps** in Sweden Central: +- **Sticky sessions** enabled for Blazor Server (session affinity) +- **Custom domain** with managed TLS certificate +- **Scaling**: 2–6 replicas (min 2 for Orleans resilience), 2 vCPU / 4Gi per replica ## PostgreSQL @@ -83,10 +190,11 @@ Deployed modes (`test`, `prod`) run on **Azure Container Apps** in Sweden Centra ## Azure Blob Storage -Content files (attachments, documents) are stored in Azure Blob Storage. +Content files (attachments, documents) and data protection keys are stored in Azure Blob Storage. -- **Local**: Azurite emulator with persistent data bind mount +- **Local**: Azurite emulator with persistent data bind mount (`Azurite/Data/`) - **Deployed**: Azure Storage Account provisioned in Sweden Central +- **local-test/local-prod**: Connects via Azure Identity (`az login`), no secrets needed ## Orleans @@ -97,47 +205,107 @@ Orleans provides distributed actor clustering for the microservices deployment. ## Application Insights -Telemetry and distributed tracing via Azure Application Insights, provisioned automatically in all deployed modes. +Telemetry and distributed tracing via Azure Application Insights, provisioned automatically in all modes. + +# Secrets Reference + +| Secret | Required | Description | +|--------|----------|-------------| +| `Parameters:azure-foundry-key` | **Yes** | Azure AI Foundry API key (LLM access) | +| `Parameters:microsoft-client-id` | **Yes** | Microsoft OAuth client ID | +| `Parameters:microsoft-client-secret` | **Yes** | Microsoft OAuth client secret (**value**, not ID) | +| `Parameters:embedding-endpoint` | No | Embedding model endpoint (embedding disabled when absent) | +| `Parameters:embedding-key` | No | Embedding model API key | +| `Parameters:embedding-model` | No | Embedding model name | +| `Parameters:microsoft-tenant-id` | No | Microsoft Entra tenant ID (defaults to `common` for multi-tenant) | +| `Parameters:google-client-id` | No | Google OAuth client ID (Google login disabled when absent) | +| `Parameters:google-client-secret` | No | Google OAuth client secret | +| `Parameters:custom-domain` | No | Custom domain for deployed portal | +| `Parameters:certificate-name` | No | TLS certificate name for custom domain | +| `ConnectionStrings:memex` | local-test/local-prod only | Azure PostgreSQL connection string | -# Secrets Management +# Project Structure -Secrets are managed via `dotnet user-secrets` locally and GitHub secrets in CI/CD. +``` +memex/aspire/ +├── Memex.AppHost/ # Aspire orchestrator (defines all resources) +│ ├── Program.cs # Mode matrix, resource definitions, parameters +│ ├── azure.yaml # Azure Developer CLI service definition +│ └── infra/ # Generated Bicep templates (committed) +├── Memex.Portal.Distributed/ # Portal with co-hosted Orleans silo +├── Memex.Portal.Orleans/ # Orleans grain interfaces +├── Memex.Portal.ServiceDefaults/# Shared service defaults (health, telemetry) +└── Memex.Database.Migration/ # Database migration project (run-to-completion) +``` + +# First-Time Deployment Checklist -Required secrets for distributed modes: +After the first `aspire deploy` completes and Azure resources are provisioned, complete these one-time setup steps: -| Secret | Description | -|--------|-------------| -| `Parameters:azure-foundry-key` | Azure AI Foundry API key (LLM access) | -| `Parameters:embedding-endpoint` | Embedding model endpoint | -| `Parameters:embedding-key` | Embedding model API key | -| `Parameters:embedding-model` | Embedding model name | -| `Parameters:microsoft-client-id` | Microsoft OAuth client ID | -| `Parameters:microsoft-client-secret` | Microsoft OAuth client secret | -| `Parameters:google-client-id` | Google OAuth client ID | -| `Parameters:google-client-secret` | Google OAuth client secret | -| `Parameters:custom-domain` | Custom domain for deployed portal | -| `Parameters:certificate-name` | TLS certificate name for custom domain | +## 1. Register Redirect URIs in Microsoft Entra -For `local-test` and `local-prod` modes, also set: +Go to the [Azure Portal](https://portal.azure.com) > App registrations > your app > Authentication > Add a platform (Web): -| Secret | Description | -|--------|-------------| -| `ConnectionStrings:memex` | Azure PostgreSQL connection string | +- Add redirect URI: `https:///signin-microsoft` +- The ACA domain is shown in the deploy output (e.g., `memex-test.whiteplant-79bbc284.swedencentral.azurecontainerapps.io`) +- If using a custom domain, add that redirect URI as well -Set secrets using: +## 2. Allow-list pgvector Extension on Azure PostgreSQL + +Azure PostgreSQL Flexible Server requires explicit extension allow-listing. Without this, the database migration fails silently on vector-related operations: ```bash -cd memex/aspire/Memex.AppHost -dotnet user-secrets set "Parameters:azure-foundry-key" "" +az postgres flexible-server parameter set \ + --resource-group \ + --server-name \ + --name azure.extensions \ + --value "vector" ``` -# Project Structure +Find the server name in the Azure portal or from the Aspire deployment output. +## 3. Restart the Database Migration + +After allow-listing pgvector, restart the `db-migration` container app so it re-runs schema initialization: + +```bash +az containerapp revision restart \ + --name db-migration \ + --resource-group \ + --revision ``` -memex/aspire/ -├── Memex.AppHost/ # Aspire orchestrator (defines all resources) -├── Memex.Portal.Distributed/ # Portal with co-hosted Orleans silo -├── Memex.Portal.Orleans/ # Orleans grain interfaces -├── Memex.Portal.ServiceDefaults/ # Shared service defaults (health, telemetry) -└── Memex.Database.Migration/ # Database migration project -``` + +Or redeploy via `aspire deploy` which rebuilds and redeploys all container apps. + +# Troubleshooting + +## "Failed to read input in non-interactive mode" +All parameters must be set via `dotnet user-secrets` before deploying. Also ensure you pass `-e Development` to `aspire deploy` — without it, user secrets are not loaded. Run `dotnet user-secrets list --project memex/aspire/Memex.AppHost` to check which are missing. + +## Aspire deployment state cache +`aspire deploy` caches parameter values in `~/.aspire/deployments//development.json`. If you update a secret via `dotnet user-secrets`, the cached value is **not** automatically refreshed. To force a refresh, either: +- Delete the cache file and redeploy (Aspire will re-read from user secrets) +- Manually edit the `Parameters` section in the cached JSON file + +## Container App not reachable after deploy +Check that `UseForwardedHeaders()` is enabled in `MemexConfiguration.cs` — Azure Container Apps uses a reverse proxy that sets `X-Forwarded-*` headers. Without forwarded headers, HTTPS redirects and OAuth callbacks fail. + +## Microsoft login: AADSTS50194 (not configured as multi-tenant) +The app registration is single-tenant but the OIDC authority URL defaults to `/common`. Set the `microsoft-tenant-id` parameter to your Entra tenant GUID (see Secrets Reference). Without it, the AppHost defaults to `common` (multi-tenant). + +## Microsoft login: AADSTS50011 (redirect URI mismatch) +The ACA URL must be registered as a redirect URI in the Microsoft Entra app registration. Add `https:///signin-microsoft` under Authentication > Web > Redirect URIs. + +## Microsoft login: AADSTS7000215 (invalid client secret) +Two common causes: +1. **Secret ID vs secret value**: The `microsoft-client-secret` parameter must be the secret **value** (shown once at creation), not the secret **ID** (a GUID). +2. **Stale deployment cache**: Even after updating `dotnet user-secrets`, the old value may persist in `~/.aspire/deployments/`. See "Aspire deployment state cache" above. + +## Microsoft login redirects to blank page +Ensure the redirect URI `https:///signin-microsoft` is registered in the Microsoft Entra app registration. The portal constructs this from the forwarded host header. + +## "function rebuild_user_effective_permissions() does not exist" +The database migration (`db-migration` container app) failed before creating schema functions. Common cause: pgvector extension was not allow-listed on Azure PostgreSQL (see First-Time Deployment Checklist above). Check db-migration logs, fix the root cause, and redeploy. + +## Sample data (ACME, Northwind, etc.) missing in deployed environment +Sample data nodes are loaded from `samples/Graph/Data/` via `AddGraph()`. Verify the container image includes these files and that the portal starts successfully (check Application Insights logs). diff --git a/src/MeshWeaver.Documentation/Data/Architecture/ProjectTemplates.md b/src/MeshWeaver.Documentation/Data/Architecture/ProjectTemplates.md new file mode 100644 index 000000000..da0b57a8a --- /dev/null +++ b/src/MeshWeaver.Documentation/Data/Architecture/ProjectTemplates.md @@ -0,0 +1,246 @@ +--- +Name: Project Templates +Category: Architecture +Description: Bootstrapping a new MeshWeaver portal with dotnet new, template structure, configuration, and customization +Icon: /static/NodeTypeIcons/code.svg +--- + +MeshWeaver ships a **.NET project template** (`meshweaver-memex`) that scaffolds a complete portal application. Running `dotnet new meshweaver-memex -o MyProject` generates a working solution with sample data, authentication, AI integration, and both monolith and distributed deployment options — ready to run in under a minute. + +# Why Templates + +Building a MeshWeaver portal from scratch requires configuring message hubs, layout areas, authentication, graph nodes, access control, and Aspire orchestration. The template handles all of this, giving you: + +- A **running portal** with sample data (ACME insurance company demo) +- **Dev login** with pre-configured users (Admin, Alice, Bob) for local development +- **Two deployment modes**: monolith (single process, no dependencies) and distributed (Aspire + Orleans + PostgreSQL) +- **Proper namespace renaming**: `dotnet new` replaces `Memex` with your project name throughout + +# Quick Start + +## Install the Template + +From a published NuGet package: + +```bash +dotnet new install MeshWeaver.ProjectTemplates +``` + +Or from a local template directory (for development): + +```bash +dotnet new install path/to/dist/templates/ +``` + +## Scaffold a New Project + +```bash +dotnet new meshweaver-memex -o MyProject +``` + +This creates a `MyProject/` directory with all projects renamed from `Memex` to `MyProject`. + +## Run the Monolith Portal + +```bash +dotnet run --project MyProject/MyProject.Portal.Monolith +``` + +Open the URL shown in the console (default: `https://localhost:7222`). The dev login page lists available users — click one to sign in. + +## Run with Aspire (Distributed) + +```bash +dotnet run --project MyProject/aspire/MyProject.AppHost +``` + +This starts the Aspire dashboard with PostgreSQL (Docker), the distributed portal with Orleans, and the database migration service. + +# What the Template Generates + +``` +MyProject/ +├── MyProject.slnx # Solution file +├── MyProject.Portal.Monolith/ # Standalone portal (no external deps) +│ ├── Program.cs # Entry point +│ ├── Properties/launchSettings.json # Dev environment & ports +│ └── appsettings.Development.json # Graph storage paths, AI config +├── MyProject.Portal.Shared/ # Shared Razor UI, auth, configuration +│ ├── Pages/ # DevLogin, Onboarding, portal pages +│ ├── Authentication/ # DevAuthController, middleware +│ └── MyProjectConfiguration.cs # Hub setup, AddGraph(), AddDocumentation() +├── aspire/ +│ ├── MyProject.AppHost/ # Aspire orchestrator +│ ├── MyProject.Portal.Distributed/ # Portal with Orleans silo +│ ├── MyProject.Database.Migration/ # Schema migration (run-to-completion) +│ └── MyProject.Portal.ServiceDefaults/ # Health, telemetry defaults +├── samples/Graph/Data/ # Sample data loaded by AddGraph() +│ ├── ACME/ # Insurance company demo +│ │ ├── Project/ # 2 projects with Todos +│ │ ├── User/ # 3 org-scoped users (Oliver, Paul, Quinn) +│ │ ├── Agent/ # TodoAgent definition +│ │ ├── Doc/ # ACME-specific documentation +│ │ └── _Access/ # Partition-level access assignments +│ └── User/ # Top-level login users +│ ├── Admin.json # Admin user +│ ├── Alice.json # Sample user +│ ├── Bob.json # Sample user +│ └── _Access/ # Global access assignments (Admin role) +├── Directory.Build.props # MSBuild properties +├── Directory.Packages.props # Centralized NuGet versions +└── nuget.config # Package sources +``` + +# Template Architecture + +## Two User Scopes + +The template includes users at two levels, mirroring the MeshWeaver convention: + +| Scope | Path | Purpose | +|-------|------|---------| +| **Global** | `User/Admin`, `User/Alice`, `User/Bob` | Portal-wide login users with `namespace: "User"` | +| **Partition** | `ACME/User/Oliver`, `ACME/User/Paul`, `ACME/User/Quinn` | Organization-scoped users with `namespace: "ACME/User"` | + +The **DevLogin page** queries `nodeType:User namespace:User` — only global users appear. Partition-scoped users (like ACME's Oliver) are visible within their organization context but do not appear on the login screen. + +## Access Control + +Each login user needs an **AccessAssignment** node granting a role. These live in `User/_Access/`: + +```json +{ + "id": "Admin_Access", + "namespace": "User/_Access", + "nodeType": "AccessAssignment", + "content": { + "$type": "AccessAssignment", + "accessObject": "Admin", + "displayName": "Admin", + "roles": [{ "role": "Admin" }] + } +} +``` + +Without an access assignment, the user can log in but receives "Access denied" errors when navigating. The template ships Admin, Alice, and Bob with the `Admin` role. + +## Graph Storage Configuration + +The monolith portal loads sample data from the filesystem via `appsettings.Development.json`: + +```json +{ + "Graph": { + "Storage": { + "Type": "FileSystem", + "BasePath": "../samples/Graph/Data" + }, + "Content": { + "Type": "FileSystem", + "BasePath": "../samples/Graph" + } + } +} +``` + +Paths are relative to the monolith project directory. The distributed portal uses PostgreSQL instead — no file paths needed. + +## What the Framework Provides + +`AddGraph()` and `AddDocumentation()` (called in the shared configuration) register built-in resources that are **not** in the template's `samples/` directory: + +- **Node types**: Markdown, Code, Agent, Group, User, VUser, Role, Notification, Approval, AccessAssignment, GroupMembership, and more +- **Documentation**: Architecture guides, DataMesh reference, GUI controls, AI integration docs (served under the `Doc/` namespace) +- **Icons**: Node type icons (`/static/NodeTypeIcons/`) +- **Roles**: Built-in Admin, Editor, Viewer role definitions + +# Customizing Your Portal + +## Adding Users + +Create a JSON file in `samples/Graph/Data/User/` and a matching access assignment in `User/_Access/`: + +```json +{ + "id": "Jane", + "namespace": "User", + "name": "Jane Doe", + "nodeType": "User", + "icon": "/static/NodeTypeIcons/person.svg", + "isPersistent": true, + "content": { + "$type": "User", + "email": "jane@example.com", + "bio": "Product manager." + } +} +``` + +```json +{ + "id": "Jane_Access", + "namespace": "User/_Access", + "nodeType": "AccessAssignment", + "content": { + "$type": "AccessAssignment", + "accessObject": "Jane", + "displayName": "Jane Doe", + "roles": [{ "role": "Admin" }] + } +} +``` + +## Adding a New Organization + +Create a directory under `samples/Graph/Data/` following the ACME pattern: + +``` +samples/Graph/Data/MyOrg/ +├── MyOrg.json # Organization root node +├── Project/ # Projects +├── User/ # Org-scoped users +├── Doc/ # Org documentation +└── _Access/ # Org-level access assignments +``` + +## Replacing Sample Data + +Delete the `ACME/` directory and add your own data. The portal loads whatever is in the `samples/Graph/Data/` directory — there are no hard-coded references to ACME. + +## Moving to Production Auth + +The DevLogin page is only active when `ASPNETCORE_ENVIRONMENT=Development`. In production, configure Microsoft or Google OAuth in the Aspire AppHost. See [Deployment](Deployment) for secrets and redirect URI setup. + +# Monolith vs Distributed + +| Aspect | Monolith | Distributed (Aspire) | +|--------|----------|---------------------| +| **Dependencies** | None | Docker (PostgreSQL, Azurite) | +| **Data storage** | Filesystem (`samples/Graph/Data/`) | PostgreSQL with pgvector | +| **Scaling** | Single process | Orleans clustering, Azure Container Apps | +| **Use case** | Local development, demos | Staging, production | +| **Run command** | `dotnet run --project MyProject.Portal.Monolith` | `dotnet run --project aspire/MyProject.AppHost` | + +Start with the monolith for development. When you need persistence, search, or multi-instance scaling, switch to the distributed mode. Both share the same `MyProject.Portal.Shared` project — all UI, configuration, and business logic is identical. + +# Troubleshooting + +## "Address already in use" on startup + +The default ports (7222/5222) are occupied. Either stop the other process or change the ports in `Properties/launchSettings.json`. + +## Dev login shows no users + +The DevLogin page queries `nodeType:User namespace:User`. Ensure you have user JSON files in `samples/Graph/Data/User/` (not just inside an organization like `ACME/User/`). + +## "Access denied" after login + +The user exists but has no access assignment. Create an `AccessAssignment` node in `User/_Access/` granting a role (Admin, Editor, or Viewer). + +## Portal crashes on startup (missing Graph:Storage) + +`ASPNETCORE_ENVIRONMENT` is not set to `Development`. Ensure `Properties/launchSettings.json` exists and sets the environment variable, or run with `--environment Development`. + +## ACME data not loading + +Check that `appsettings.Development.json` has correct relative paths. From the monolith project directory, `../samples/Graph/Data` should resolve to the `samples/` folder at the solution root. diff --git a/src/MeshWeaver.Graph/Configuration/UserNodeType.cs b/src/MeshWeaver.Graph/Configuration/UserNodeType.cs index 1991c4036..2580f7edb 100644 --- a/src/MeshWeaver.Graph/Configuration/UserNodeType.cs +++ b/src/MeshWeaver.Graph/Configuration/UserNodeType.cs @@ -103,7 +103,10 @@ private static MessageHubConfiguration WithUserNodePublicRead(this MessageHubCon // "User/Alice" is public, "User/Alice/SomeThread" is not return nodePath.StartsWith("User/", StringComparison.OrdinalIgnoreCase) && !nodePath["User/".Length..].Contains('/'); - }); + }) + .AddHubPermissionRule( + Permission.Read, + (_, userId) => !string.IsNullOrEmpty(userId)); /// /// Adds a create-access rule for portal namespace hubs (onboarding flow). diff --git a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSchemaInitializer.cs b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSchemaInitializer.cs index 51e365907..80118e631 100644 --- a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSchemaInitializer.cs +++ b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSchemaInitializer.cs @@ -1198,6 +1198,27 @@ AFTER INSERT OR UPDATE OR DELETE ON mesh_nodes END IF; END; $$; + + -- Simple access_control and group_members tables used by convenience methods + CREATE TABLE IF NOT EXISTS access_control ( + node_path TEXT NOT NULL, + subject TEXT NOT NULL, + permission TEXT NOT NULL, + is_allow BOOLEAN NOT NULL, + PRIMARY KEY (node_path, subject, permission) + ); + + CREATE TABLE IF NOT EXISTS group_members ( + group_name TEXT NOT NULL, + member_id TEXT NOT NULL, + PRIMARY KEY (group_name, member_id) + ); + + -- Node type permission flags (populated from DI-registered NodeTypePermission records) + CREATE TABLE IF NOT EXISTS node_type_permissions ( + node_type TEXT NOT NULL PRIMARY KEY, + public_read BOOLEAN NOT NULL DEFAULT false + ); """; } } From 387d8ac36da41131528affe7aca90e1af83d1ed4 Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Thu, 2 Apr 2026 09:25:43 +0200 Subject: [PATCH 04/14] cleanup; adding CosmosImport README.md for nuget --- .../AB_YSoGD_kGFC6EpsSGjBw.json | 17 ----------------- .../AfOt7ViXj0ysQhPHnV27UA.json | 18 ------------------ .../FqRly-CgXk2VKVD4EhtZag.json | 17 ----------------- .../RgF2N5EYYUqBdbcNYXxc-g.json | 18 ------------------ .../YSO1I0uWvkm7aDRFlT05GQ.json | 17 ----------------- .../Zm6XFWDJm0ekeGS6GlEJVg.json | 18 ------------------ .../dz6qM4tcZEK5-2EZNSJ3eg.json | 17 ----------------- .../w_xpEqMz7EqSSWEJK-e7_A.json | 18 ------------------ tools/MeshWeaver.Tools.CosmosImport/README.md | 3 +++ 9 files changed, 3 insertions(+), 140 deletions(-) delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AB_YSoGD_kGFC6EpsSGjBw.json delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AfOt7ViXj0ysQhPHnV27UA.json delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/FqRly-CgXk2VKVD4EhtZag.json delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/RgF2N5EYYUqBdbcNYXxc-g.json delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/YSO1I0uWvkm7aDRFlT05GQ.json delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/Zm6XFWDJm0ekeGS6GlEJVg.json delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/dz6qM4tcZEK5-2EZNSJ3eg.json delete mode 100644 samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/w_xpEqMz7EqSSWEJK-e7_A.json create mode 100644 tools/MeshWeaver.Tools.CosmosImport/README.md diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AB_YSoGD_kGFC6EpsSGjBw.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AB_YSoGD_kGFC6EpsSGjBw.json deleted file mode 100644 index 2c029c991..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AB_YSoGD_kGFC6EpsSGjBw.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AB_YSoGD_kGFC6EpsSGjBw", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AB_YSoGD_kGFC6EpsSGjBw", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T12:42:05.592598+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "AB_YSoGD_kGFC6EpsSGjBw", - "role": "user", - "text": "https://localhost:7122/Northwind/Reports", - "timestamp": "2026-02-26T12:42:05.592041Z", - "type": "ExecutedInput" - } -} \ No newline at end of file diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AfOt7ViXj0ysQhPHnV27UA.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AfOt7ViXj0ysQhPHnV27UA.json deleted file mode 100644 index 75a8ce861..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AfOt7ViXj0ysQhPHnV27UA.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AfOt7ViXj0ysQhPHnV27UA", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/AfOt7ViXj0ysQhPHnV27UA", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T10:39:55.400615+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "AfOt7ViXj0ysQhPHnV27UA", - "role": "TodoAgent", - "authorName": "TodoAgent", - "text": "# Cornerstone\n\nI don\u0027t have specific information about \u0022Cornerstone\u0022 in my current context. What I do have access to is the **ACME project system**, which includes:\n\n- **Task/Todo management** for ACME projects\n- **Customer data** (like the attached Northwind customer record for **Antonio Moreno Taquer\u00EDa**)\n- **Team member information** for ACME employees and the platform team\n\nIf you\u0027re asking about a specific ACME insurance product, policy, or related tasks, could you clarify what you\u0027re looking for? For example:\n\n- **Tasks related to insurance** \u2014 I can search for or create todos in categories like Compliance, Risk, or Legal\n- **Customer information** \u2014 I can look up customer records if they exist in the system\n- **Something else entirely** \u2014 Let me know and I\u0027ll do my best to help\n\nWhat would you like to do?", - "timestamp": "2026-02-26T10:39:55.400172Z", - "type": "AgentResponse" - } -} \ No newline at end of file diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/FqRly-CgXk2VKVD4EhtZag.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/FqRly-CgXk2VKVD4EhtZag.json deleted file mode 100644 index f4e746bca..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/FqRly-CgXk2VKVD4EhtZag.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/FqRly-CgXk2VKVD4EhtZag", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/FqRly-CgXk2VKVD4EhtZag", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T10:39:47.026119+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "FqRly-CgXk2VKVD4EhtZag", - "role": "user", - "text": "What can you tell me about ACME insurance?", - "timestamp": "2026-02-26T10:39:47.025548Z", - "type": "ExecutedInput" - } -} \ No newline at end of file diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/RgF2N5EYYUqBdbcNYXxc-g.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/RgF2N5EYYUqBdbcNYXxc-g.json deleted file mode 100644 index 6e88cbf96..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/RgF2N5EYYUqBdbcNYXxc-g.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/RgF2N5EYYUqBdbcNYXxc-g", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/RgF2N5EYYUqBdbcNYXxc-g", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T12:41:53.725749+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "RgF2N5EYYUqBdbcNYXxc-g", - "role": "TodoAgent", - "authorName": "TodoAgent", - "text": "I don\u0027t have a tool available to check which page or project you\u0027re currently viewing. I can only work with the tools provided to me, and I don\u0027t have access to any layout, navigation, or data plugin tools that would let me determine your current page context.\n\nCould you let me know which project or page you\u0027re on? That way I can help you with your tasks more effectively.", - "timestamp": "2026-02-26T12:41:53.725399Z", - "type": "AgentResponse" - } -} \ No newline at end of file diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/YSO1I0uWvkm7aDRFlT05GQ.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/YSO1I0uWvkm7aDRFlT05GQ.json deleted file mode 100644 index b727ed3e9..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/YSO1I0uWvkm7aDRFlT05GQ.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/YSO1I0uWvkm7aDRFlT05GQ", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/YSO1I0uWvkm7aDRFlT05GQ", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T12:41:47.703073+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "YSO1I0uWvkm7aDRFlT05GQ", - "role": "user", - "text": "which page are we on?", - "timestamp": "2026-02-26T12:41:47.700801Z", - "type": "ExecutedInput" - } -} \ No newline at end of file diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/Zm6XFWDJm0ekeGS6GlEJVg.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/Zm6XFWDJm0ekeGS6GlEJVg.json deleted file mode 100644 index 7a6464c2c..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/Zm6XFWDJm0ekeGS6GlEJVg.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/Zm6XFWDJm0ekeGS6GlEJVg", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/Zm6XFWDJm0ekeGS6GlEJVg", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T12:42:13.400265+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "Zm6XFWDJm0ekeGS6GlEJVg", - "role": "TodoAgent", - "authorName": "TodoAgent", - "text": "I appreciate you sharing that context, but I should be transparent: I don\u0027t have access to the tools mentioned in those instructions (like \u0060GetData\u0060, \u0060UpdateData\u0060, \u0060GetLayoutAreas\u0060, \u0060DisplayLayoutArea\u0060, or \u0060DataPlugin\u0060). These tools are not available in my current environment.\n\nI\u0027m Claude Code, a software engineering assistant. Here\u0027s what I **can** help you with:\n\n- **Software engineering tasks** - writing, debugging, and refactoring code\n- **Git operations** - commits, branches, PRs\n- **File management** - reading, writing, and editing files\n- **Web searches and research**\n- **General coding questions**\n\nIf you\u0027re working on a todo/task management system and need help with the code behind it, I\u0027d be happy to assist with that. What can I help you with today?", - "timestamp": "2026-02-26T12:42:13.399729Z", - "type": "AgentResponse" - } -} \ No newline at end of file diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/dz6qM4tcZEK5-2EZNSJ3eg.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/dz6qM4tcZEK5-2EZNSJ3eg.json deleted file mode 100644 index 47aa81555..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/dz6qM4tcZEK5-2EZNSJ3eg.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/dz6qM4tcZEK5-2EZNSJ3eg", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/dz6qM4tcZEK5-2EZNSJ3eg", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T10:38:58.355093+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "dz6qM4tcZEK5-2EZNSJ3eg", - "role": "user", - "text": "Hello, who\u0027s this?", - "timestamp": "2026-02-26T10:38:58.353561Z", - "type": "ExecutedInput" - } -} \ No newline at end of file diff --git a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/w_xpEqMz7EqSSWEJK-e7_A.json b/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/w_xpEqMz7EqSSWEJK-e7_A.json deleted file mode 100644 index a5092ca79..000000000 --- a/samples/Graph/Data/Cornerstone/VV8nfr2LjEKFulwmHXw8RA/w_xpEqMz7EqSSWEJK-e7_A.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$type": "MeshNode", - "id": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/w_xpEqMz7EqSSWEJK-e7_A", - "path": "Cornerstone/VV8nfr2LjEKFulwmHXw8RA/w_xpEqMz7EqSSWEJK-e7_A", - "nodeType": "ThreadMessage", - "icon": "/static/NodeTypeIcons/message.svg", - "lastModified": "2026-02-26T10:39:06.160758+00:00", - "state": "Active", - "content": { - "$type": "ThreadMessage", - "id": "w_xpEqMz7EqSSWEJK-e7_A", - "role": "TodoAgent", - "authorName": "TodoAgent", - "text": "This is **Antonio Moreno Taquer\u00EDa**, a customer record from the Northwind system. Here\u0027s a quick summary:\n\n| Field | Details |\n|-------|---------|\n| **Contact** | Antonio Moreno |\n| **Title** | Owner |\n| **Company** | Antonio Moreno Taquer\u00EDa |\n| **City** | M\u00E9xico D.F., Mexico |\n| **Postal Code** | 05023 |\n| **Phone** | (5) 555-3932 |\n| **Status** | Active |\n\nIs there anything you\u0027d like to do with this customer record \u2014 for example, create a task related to them?", - "timestamp": "2026-02-26T10:39:06.160494Z", - "type": "AgentResponse" - } -} \ No newline at end of file diff --git a/tools/MeshWeaver.Tools.CosmosImport/README.md b/tools/MeshWeaver.Tools.CosmosImport/README.md new file mode 100644 index 000000000..c719b57a2 --- /dev/null +++ b/tools/MeshWeaver.Tools.CosmosImport/README.md @@ -0,0 +1,3 @@ +# MeshWeaver.Tools.CosmosImport + +CLI tool for importing data from Azure Cosmos DB into MeshWeaver. From a51b6d18430a503796cf4fa57b674d1607e96d6c Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Thu, 9 Apr 2026 12:46:32 +0200 Subject: [PATCH 05/14] fixed unit tests (also AI & ACME); hub vs. group rel'ship; fixed local mode; clean up --- .../Authentication/VirtualUserMiddleware.cs | 7 +- memex/Memex.Portal.Shared/Pages/Index.razor | 12 +- memex/Memex.Portal.Shared/Pages/Login.razor | 16 +- .../Pages/Onboarding.razor | 205 +- memex/Memex.Portal.Shared/Pages/Welcome.razor | 28 + memex/aspire/Memex.AppHost/Program.cs | 63 +- .../Memex.Database.Migration/Program.cs | 13 +- .../Data/FutuRe/AmericasIns/Analysis.json | 7780 ++++++++++++++++- .../LineOfBusiness/AGRICULTURE.json | 2 +- .../LineOfBusiness/COMMERCIAL.json | 2 +- .../LineOfBusiness/CYBER_TECH.json | 2 +- .../LineOfBusiness/ENERGY_MINING.json | 2 +- .../LineOfBusiness/HOMEOWNERS.json | 2 +- .../AmericasIns/LineOfBusiness/LIFE_ANN.json | 2 +- .../LineOfBusiness/SPECIALTY_AVTN_US.json | 2 +- .../LineOfBusiness/WORKERS_COMP.json | 2 +- .../_Source/ExternalDependencies.cs | 7 + .../Graph/Data/FutuRe/AsiaRe/Analysis.json | 7780 ++++++++++++++++- .../_Source/ExternalDependencies.cs | 7 + samples/Graph/Data/FutuRe/DataDistribution.md | 40 +- .../Graph/Data/FutuRe/EuropeRe/Analysis.json | 7780 ++++++++++++++++- .../EuropeRe/LineOfBusiness/COMM_FIRE.json | 2 +- .../EuropeRe/LineOfBusiness/HOUSEHOLD.json | 2 +- .../EuropeRe/LineOfBusiness/LIABILITY.json | 2 +- .../LineOfBusiness/LIFE_HEALTH_EU.json | 2 +- .../FutuRe/EuropeRe/LineOfBusiness/MOTOR.json | 2 +- .../LineOfBusiness/SPECIALTY_AVTN.json | 2 +- .../EuropeRe/LineOfBusiness/TECH_RISK.json | 2 +- .../EuropeRe/LineOfBusiness/TRANSPORT.json | 2 +- .../_Source/ExternalDependencies.cs | 7 + .../GroupAnalysis/_Source/AnalysisContent.cs | 23 + .../GroupAnalysis/_Source/FutuReDataLoader.cs | 139 +- samples/Graph/Data/FutuRe/WhyDataMesh.md | 2 +- samples/Graph/Data/FutuRe/index.md | 4 +- .../FutuRe/AmericasIns/Analysis/datacube.csv | 865 -- .../FutuRe/AsiaRe/Analysis/datacube.csv | 865 -- .../FutuRe/EuropeRe/Analysis/datacube.csv | 865 -- .../Infrastructure/UserContextMiddleware.cs | 14 + .../Data/Architecture/Deployment.md | 16 +- .../Data/DataMesh/DataConfiguration.md | 90 + .../BlazorHostingExtensions.cs | 1 - .../SchemaValidationTest.cs | 3 +- .../TodoCreateFlowTest.cs | 4 +- .../FutuReAnalysisTest.cs | 4 +- .../MeshWeaver.FutuRe.Test.csproj | 1 + 45 files changed, 23820 insertions(+), 2853 deletions(-) create mode 100644 samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs create mode 100644 samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs create mode 100644 samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs delete mode 100644 samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv delete mode 100644 samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv delete mode 100644 samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv diff --git a/memex/Memex.Portal.Shared/Authentication/VirtualUserMiddleware.cs b/memex/Memex.Portal.Shared/Authentication/VirtualUserMiddleware.cs index 233de8258..e8cbddb3c 100644 --- a/memex/Memex.Portal.Shared/Authentication/VirtualUserMiddleware.cs +++ b/memex/Memex.Portal.Shared/Authentication/VirtualUserMiddleware.cs @@ -23,10 +23,13 @@ public class VirtualUserMiddleware(RequestDelegate next, ILogger path.StartsWith(p, StringComparison.OrdinalIgnoreCase))) { await next(context); return; diff --git a/memex/Memex.Portal.Shared/Pages/Index.razor b/memex/Memex.Portal.Shared/Pages/Index.razor index 708123bd9..ec5a34ed9 100644 --- a/memex/Memex.Portal.Shared/Pages/Index.razor +++ b/memex/Memex.Portal.Shared/Pages/Index.razor @@ -13,13 +13,15 @@ } @code { + private AccessContext? UserContext => AccessService?.Context ?? AccessService?.CircuitContext; + private bool IsRealUser => - AccessService?.Context != null - && !string.IsNullOrEmpty(AccessService.Context.ObjectId) - && !AccessService.Context.IsVirtual - && !string.Equals(AccessService.Context.ObjectId, WellKnownUsers.Anonymous, StringComparison.OrdinalIgnoreCase); + UserContext != null + && !string.IsNullOrEmpty(UserContext.ObjectId) + && !UserContext.IsVirtual + && !string.Equals(UserContext.ObjectId, WellKnownUsers.Anonymous, StringComparison.OrdinalIgnoreCase); - private string UserAddress => $"User/{AccessService?.Context?.ObjectId}"; + private string UserAddress => $"User/{UserContext?.ObjectId}"; protected override void OnInitialized() { diff --git a/memex/Memex.Portal.Shared/Pages/Login.razor b/memex/Memex.Portal.Shared/Pages/Login.razor index cbcc62610..1c3b41c81 100644 --- a/memex/Memex.Portal.Shared/Pages/Login.razor +++ b/memex/Memex.Portal.Shared/Pages/Login.razor @@ -1,4 +1,5 @@ @page "/login" +@using Microsoft.AspNetCore.Components.Authorization @using MeshWeaver.Blazor.Portal.Authentication @inject IAuthenticationNavigationService AuthNavService @inject NavigationManager Navigation @@ -51,6 +52,9 @@ [SupplyParameterFromQuery(Name = "error")] public string? ErrorMessage { get; set; } + [CascadingParameter] + private Task? AuthStateTask { get; set; } + private IReadOnlyList Providers { get; set; } = []; private bool ShowDevLogin { get; set; } @@ -60,8 +64,18 @@ Navigation.NavigateTo(url, forceLoad: true); } - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { + if (AuthStateTask is not null) + { + var authState = await AuthStateTask; + if (authState.User?.Identity?.IsAuthenticated == true) + { + Navigation.NavigateTo(ReturnUrl ?? "/", forceLoad: true); + return; + } + } + if (AuthNavService is AuthenticationNavigationService navService) { Providers = navService.GetAvailableProviders(); diff --git a/memex/Memex.Portal.Shared/Pages/Onboarding.razor b/memex/Memex.Portal.Shared/Pages/Onboarding.razor index 7036bf697..82777120d 100644 --- a/memex/Memex.Portal.Shared/Pages/Onboarding.razor +++ b/memex/Memex.Portal.Shared/Pages/Onboarding.razor @@ -5,105 +5,159 @@ @using MeshWeaver.Mesh.Security @using MeshWeaver.Mesh.Services @using MeshWeaver.Messaging +@using MeshWeaver.Hosting.Blazor @using Microsoft.Extensions.DependencyInjection @inject AccessService AccessService @inject IMeshService NodeFactory @inject IMeshService MeshQuery @inject PortalApplication PortalApplication @inject NavigationManager Navigation +@inject CircuitAccessHandler CircuitAccessHandler Complete Your Profile - Memex Portal -
-
-
- -

Complete Your Profile

-

Tell us a bit about yourself to get started

+@if (!checkCompleted || existingUserFound) +{ +
+
+ +

@(existingUserFound ? "Redirecting..." : "Loading...")

+
+} +else +{ +
+
+
+ +

Complete Your Profile

+

Tell us a bit about yourself to get started

+
- @if (!string.IsNullOrEmpty(errorMessage)) - { - - @errorMessage - - } + @if (!string.IsNullOrEmpty(errorMessage)) + { + + @errorMessage + + } + + + + + + - - - - - - - - - - - - - - - - - - Get Started - - - + + + + + + + + + + + + Get Started + + + +
-
+} @code { private OnboardingModel model = new(); private bool isSaving; private bool emailReadOnly; private string? errorMessage; + private bool checkCompleted; + private bool existingUserFound; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { - var context = AccessService?.Context; - if (context != null) - { - model.Email = context.Email ?? ""; + var context = AccessService?.Context ?? AccessService?.CircuitContext; + if (context == null) { checkCompleted = true; return; } - // Only lock the email field if we got a valid email from OAuth - emailReadOnly = !string.IsNullOrEmpty(context.Email) && context.Email.Contains('@'); + model.Email = context.Email ?? ""; - // Pre-populate full name from OAuth claims - if (!string.IsNullOrEmpty(context.Name) && context.Name != "Unknown") - model.FullName = context.Name; + // Only lock the email field if we got a valid email from OAuth + emailReadOnly = !string.IsNullOrEmpty(context.Email) && context.Email.Contains('@'); - // Suggest username from email prefix (lowercase) - if (!string.IsNullOrEmpty(context.Email) && context.Email.Contains('@')) - model.Username = context.Email.Split('@')[0].ToLowerInvariant(); + // Pre-populate full name from OAuth claims + if (!string.IsNullOrEmpty(context.Name) && context.Name != "Unknown") + model.FullName = context.Name; + + // Suggest username from email prefix (lowercase) + if (!string.IsNullOrEmpty(context.Email) && context.Email.Contains('@')) + model.Username = context.Email.Split('@')[0].ToLowerInvariant(); + + // Check if a User node already exists for this email (e.g., created via another portal) + if (!string.IsNullOrEmpty(context.Email)) + { + using (AccessService!.ImpersonateAsHub(PortalApplication!.Hub)) + { + var existing = await MeshQuery.QueryAsync( + $"nodeType:User namespace:User content.email:{context.Email} limit:1") + .FirstOrDefaultAsync(); + + if (existing is { State: MeshNodeState.Active }) + { + // Adopt existing identity and skip onboarding + var updated = (AccessService.Context ?? new AccessContext()) with + { + ObjectId = existing.Id, + Name = existing.Name ?? existing.Id, + Email = context.Email + }; + AccessService.SetContext(updated); + // Update the circuit-level context so subsequent client-side + // navigations (e.g., to Index.razor) see the resolved identity. + CircuitAccessHandler.UpdateUserContext(updated); + existingUserFound = true; + checkCompleted = true; + return; + } + } + } + checkCompleted = true; + } + + protected override Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender && existingUserFound) + { + Navigation.NavigateTo("/"); // Client-side only, no forceLoad } + return Task.CompletedTask; } private async Task HandleSubmit() @@ -119,7 +173,8 @@ try { - var userId = AccessService?.Context?.ObjectId; + var userId = AccessService?.Context?.ObjectId + ?? AccessService?.CircuitContext?.ObjectId; if (string.IsNullOrEmpty(userId)) { errorMessage = "Not authenticated. Please sign in again."; diff --git a/memex/Memex.Portal.Shared/Pages/Welcome.razor b/memex/Memex.Portal.Shared/Pages/Welcome.razor index 111ed6a00..ed70f5a51 100644 --- a/memex/Memex.Portal.Shared/Pages/Welcome.razor +++ b/memex/Memex.Portal.Shared/Pages/Welcome.razor @@ -1,5 +1,7 @@ @page "/welcome" +@using Microsoft.AspNetCore.Components.Authorization @using MeshWeaver.Blazor.Layouts +@inject NavigationManager Navigation @layout EmptyLayout Welcome - Memex Portal @@ -75,6 +77,32 @@
@code { + [CascadingParameter] + private Task? AuthStateTask { get; set; } + + private bool isAuthenticated; + + protected override async Task OnInitializedAsync() + { + if (AuthStateTask is not null) + { + var authState = await AuthStateTask; + isAuthenticated = authState.User?.Identity?.IsAuthenticated == true; + } + } + + protected override Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender && isAuthenticated) + { + // Client-side navigation to /onboarding (no forceLoad) avoids + // re-triggering the HTTP middleware pipeline which can cause redirect loops. + // Onboarding.razor handles already-onboarded users by redirecting to /. + Navigation.NavigateTo("/onboarding"); + } + return Task.CompletedTask; + } + private static class Icons { public static class Regular diff --git a/memex/aspire/Memex.AppHost/Program.cs b/memex/aspire/Memex.AppHost/Program.cs index 3591c12b7..e031d64f3 100644 --- a/memex/aspire/Memex.AppHost/Program.cs +++ b/memex/aspire/Memex.AppHost/Program.cs @@ -4,17 +4,15 @@ var builder = DistributedApplication.CreateBuilder(args); -// Mode: "local" (default), "local-test", "local-prod", "test", "prod", "monolith" -// Pass as command line argument: dotnet run -- --mode local-test +// Mode: "local" (default), "test", "prod", "monolith" +// Pass as command line argument: dotnet run -- --mode test // // Mode matrix: // Mode | PostgreSQL | Blob Storage | Orleans | Portal Name // ----------- | ----------------------- | ------------ | ---------- | ----------- -// local | Docker pgvector (memex) | Emulated | Emulated | memex-local -// local-test | Azure (memex-test) | Azure (meshweavermemextest) | Emulated | memex-local -// local-prod | Azure (memex) | Azure (meshweavermemex) | Emulated | memex-local -// test | Azure (memex-test) | Azure (meshweavermemextest) | Azure | memex-test -// prod | Azure (memex) | Azure (meshweavermemex) | Azure | memex-prod +// local | Docker pgvector (memex) | Emulated | Emulated | memex-local +// test | Azure (memex-test) | Azure | Azure | memex-test +// prod | Azure (memex) | Azure | Azure | memex-prod // monolith | FileSystem (standalone) | — | — | memex-monolith // // Secrets: set locally via `dotnet user-secrets`, in CI/CD via GitHub secrets. @@ -27,10 +25,7 @@ // Parameters:embedding-model // Parameters:microsoft-client-id // Parameters:microsoft-client-secret -// -// For local-test/local-prod, also set the connection string to the Azure PostgreSQL: -// ConnectionStrings:memex (Azure PostgreSQL, bypassing provisioning) -// Blob Storage uses RunAsExisting with Azure Identity (az login) — no secrets needed. +// Parameters:microsoft-tenant-id var mode = builder.Configuration["mode"]?.ToLowerInvariant() ?? "local"; @@ -39,6 +34,7 @@ // Standalone portal without Orleans or external infrastructure builder .AddProject("memex-monolith") + .WithEnvironment("ASPNETCORE_ENVIRONMENT", "Development") .WithExternalHttpEndpoints(); builder.Build().Run(); return; @@ -49,18 +45,17 @@ // LLM API key (single Azure Foundry key for both Anthropic and OpenAI endpoints) var azureFoundryKey = builder.AddParameter("azure-foundry-key", secret: true); -// Embedding configuration +// Authentication (Microsoft is required; Google is optional for local) +var microsoftClientId = builder.AddParameter("microsoft-client-id", secret: false); +var microsoftClientSecret = builder.AddParameter("microsoft-client-secret", secret: true); +var microsoftTenantId = builder.AddParameter("microsoft-tenant-id", secret: false); + +// Embedding, Google auth, and custom domain var embeddingEndpoint = builder.AddParameter("embedding-endpoint", secret: false); var embeddingKey = builder.AddParameter("embedding-key", secret: true); var embeddingModel = builder.AddParameter("embedding-model", secret: false); - -// Authentication -var microsoftClientId = builder.AddParameter("microsoft-client-id", secret: false); -var microsoftClientSecret = builder.AddParameter("microsoft-client-secret", secret: true); var googleClientId = builder.AddParameter("google-client-id", secret: false); var googleClientSecret = builder.AddParameter("google-client-secret", secret: true); - -// --- Custom domain (for deployed modes) --- var customDomain = builder.AddParameter("custom-domain", secret: false); var certificateName = builder.AddParameter("certificate-name", secret: false); @@ -115,9 +110,9 @@ // --- Database Migration --- var dbMigration = builder .AddProject("db-migration") + .WithEnvironment("Embedding__Model", embeddingModel) .WithReference(appInsights) - .WaitFor(appInsights) - .WithEnvironment("Embedding__Model", embeddingModel); + .WaitFor(appInsights); // --- Portal (co-hosted Orleans silo + web) --- var portal = builder @@ -125,6 +120,8 @@ .WithExternalHttpEndpoints() .WithReference(orleans) .WithReference(appInsights) + // Local modes need Development environment for static web assets (_framework, _content) + .WithEnvironment("ASPNETCORE_ENVIRONMENT", isDeployed ? "Production" : "Development") // Embedding .WithEnvironment("Embedding__Endpoint", embeddingEndpoint) .WithEnvironment("Embedding__ApiKey", embeddingKey) @@ -144,10 +141,19 @@ .WithEnvironment("AzureOpenAIS__ApiKey", azureFoundryKey) .WithEnvironment("AzureOpenAIS__Models__0", "gpt-5-mini") .WithEnvironment("AzureOpenAIS__Models__1", "gpt-5.4") + // LLM: Azure AI Foundry (multi-model inference endpoint) + .WithEnvironment("AzureAIS__Endpoint", "https://fy-meshweaver3-dev-swc-001.services.ai.azure.com/models") + .WithEnvironment("AzureAIS__ApiKey", azureFoundryKey) + .WithEnvironment("AzureAIS__Models__0", "gpt-5.4") + .WithEnvironment("AzureAIS__Models__1", "gpt-5.3-codex") + .WithEnvironment("AzureAIS__Models__2", "Mistral-Large-3") + .WithEnvironment("AzureAIS__Models__3", "DeepSeek-V3.2") + .WithEnvironment("AzureAIS__Order", "1") // Authentication .WithEnvironment("Authentication__EnableDevLogin", mode != "prod" ? "true" : "false") .WithEnvironment("Authentication__Microsoft__ClientId", microsoftClientId) .WithEnvironment("Authentication__Microsoft__ClientSecret", microsoftClientSecret) + .WithEnvironment("Authentication__Microsoft__TenantId", microsoftTenantId) .WithEnvironment("Authentication__Google__ClientId", googleClientId) .WithEnvironment("Authentication__Google__ClientSecret", googleClientSecret) // Wait for dependencies @@ -178,15 +184,6 @@ var storageBlobs = contentStorage.AddBlobs("storage"); portal.WithReference(storageBlobs).WaitFor(storageBlobs); } -else if (mode is "local-test" or "local-prod") -{ - // Connect to existing Azure Blob Storage via Azure Identity (az login, no secrets needed) - var storageName = mode is "local-test" ? "meshweavermemextest" : "meshweavermemex"; - var contentStorage = builder.AddAzureStorage("memexblobs") - .RunAsExisting(storageName, null); - var storageBlobs = contentStorage.AddBlobs("storage"); - portal.WithReference(storageBlobs); -} else { // Deployed modes: provision Azure Blob Storage in Sweden Central @@ -216,14 +213,6 @@ dbMigration.WithReference(db).WaitFor(db); portal.WithReference(db).WaitFor(db); } -else if (mode is "local-test" or "local-prod") -{ - // Use pre-configured connection string (set via dotnet user-secrets) - // to connect to existing Azure PostgreSQL without Aspire provisioning. - var db = builder.AddConnectionString("memex"); - dbMigration.WithReference(db); - portal.WithReference(db); -} else { // Deployed modes: provision Azure PostgreSQL Flexible Server in Sweden Central diff --git a/memex/aspire/Memex.Database.Migration/Program.cs b/memex/aspire/Memex.Database.Migration/Program.cs index 0ae7907a1..d578cf956 100644 --- a/memex/aspire/Memex.Database.Migration/Program.cs +++ b/memex/aspire/Memex.Database.Migration/Program.cs @@ -7,12 +7,10 @@ using MeshWeaver.Mesh; using Npgsql; -Console.WriteLine("[Migration] Starting..."); var builder = Host.CreateApplicationBuilder(args); builder.AddServiceDefaults(); var connectionString = builder.Configuration.GetConnectionString("memex") ?? ""; -Console.WriteLine($"[Migration] ConnectionString: {(string.IsNullOrEmpty(connectionString) ? "(empty)" : connectionString[..Math.Min(30, connectionString.Length)] + "...")}"); if (connectionString.Contains("database.azure.com")) builder.AddAzureNpgsqlDataSource("memex"); else @@ -26,14 +24,10 @@ o.VectorDimensions = embeddingOptions.Dimensions; }); -Console.WriteLine("[Migration] Building host..."); var host = builder.Build(); -Console.WriteLine("[Migration] Host built. Resolving services..."); var logger = host.Services.GetRequiredService().CreateLogger("Migration"); -Console.WriteLine("[Migration] Resolving NpgsqlDataSource..."); var dataSource = host.Services.GetRequiredService(); -Console.WriteLine("[Migration] NpgsqlDataSource resolved."); var options = host.Services.GetRequiredService>(); logger.LogInformation("Running database migration..."); @@ -42,8 +36,9 @@ // (portal, migration) can create per-organization schemas at runtime. if (connectionString.Contains("database.azure.com")) { + var dbName = new NpgsqlConnectionStringBuilder(connectionString).Database ?? "memex"; await using var grantCmd = dataSource.CreateCommand( - "GRANT CREATE ON DATABASE memex TO azure_pg_admin"); + $"GRANT CREATE ON DATABASE \"{dbName}\" TO azure_pg_admin"); await grantCmd.ExecuteNonQueryAsync(); logger.LogInformation("Granted CREATE ON DATABASE to azure_pg_admin."); } @@ -122,7 +117,7 @@ AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' if (isFreshDb) { logger.LogInformation("Fresh database detected — skipping data repairs (no existing data to fix)."); - currentVersion = 1; // Skip all repair migrations + currentVersion = 5; // Skip all repair migrations (no existing data to fix) } // ── Data repair v1: Move AccessAssignments to correct table + namespace ── @@ -397,7 +392,7 @@ IF NOT assignment_exists THEN 'User/' || user_rec.id, NOW(), 1, - 'Active' + 2 ); RAISE NOTICE 'Created self-assignment for user %', user_rec.id; END IF; diff --git a/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json b/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json index d2c18ef1a..3cb9c95cf 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json @@ -12,6 +12,7784 @@ "$type": "AnalysisContent", "id": "Analysis", "name": "AmericasIns Profitability Analysis", - "description": "Interactive profitability analysis for AmericasIns with local lines of business, estimates vs actuals, and quarterly trends." + "description": "Interactive profitability analysis for AmericasIns with local lines of business, estimates vs actuals, and quarterly trends.", + "datacube": [ + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 10885000.0, + "actual": 11102700.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1428000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14280000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 32342613.0, + "actual": 32989465.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4896000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48960000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4656000.0, + "actual": 4749120.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1020000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10200000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 23031067.0, + "actual": 23491688.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3366000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 33660000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 51605987.0, + "actual": 52638107.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6324000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 65720000.0, + "actual": 67034400.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21318000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3876000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38760000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11566800.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1836000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18360000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 26493600.0, + "actual": 27023472.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4284000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 42840000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 9902200.0, + "actual": 9605134.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1358000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13580000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 31113813.0, + "actual": 30180399.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4656000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46560000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5136000.0, + "actual": 4981920.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 970000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9700000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 21183067.0, + "actual": 20547575.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3201000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 32010000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 48360101.0, + "actual": 46909298.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6014000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 63240000.0, + "actual": 61342800.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20273000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3686000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36860000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 10999800.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1746000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17460000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 25384800.0, + "actual": 24623256.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4074000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 40740000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 8919400.0, + "actual": 9365370.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1470000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14700000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 29885013.0, + "actual": 31379264.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 5040000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 50400000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5424000.0, + "actual": 5695200.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1050000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10500000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 20443867.0, + "actual": 21466060.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3465000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 34650000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 41991600.0, + "actual": 44091180.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6510000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 58900000.0, + "actual": 61845000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21945000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3990000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39900000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11907000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1890000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18900000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 23610720.0, + "actual": 24791256.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4410000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 44100000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 7936600.0, + "actual": 7777868.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1372000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13720000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 29393493.0, + "actual": 28805623.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4704000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 47040000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5904000.0, + "actual": 5785920.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 980000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9800000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 21737467.0, + "actual": 21302718.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3234000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 32340000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 40578139.0, + "actual": 39766576.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6076000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 54560000.0, + "actual": 53468800.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20482000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3724000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 37240000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11113200.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1764000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17640000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 22723680.0, + "actual": 22269206.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4116000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 41160000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 7936600.0, + "actual": 8015966.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1414000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14140000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 31113813.0, + "actual": 31424951.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4848000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48480000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5424000.0, + "actual": 5478240.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1010000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10100000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 22291867.0, + "actual": 22514786.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3333000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 33330000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 41745056.0, + "actual": 42162507.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6262000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 57660000.0, + "actual": 58236600.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21109000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3838000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38380000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11453400.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1818000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18180000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 24276000.0, + "actual": 24518760.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4242000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 42420000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 8264200.0, + "actual": 7933632.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1344000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13440000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 29885013.0, + "actual": 28689612.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4608000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46080000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4944000.0, + "actual": 4746240.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 960000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9600000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 21183067.0, + "actual": 20335744.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3168000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 31680000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 39998842.0, + "actual": 38398888.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 5952000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 55800000.0, + "actual": 53568000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20064000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3648000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36480000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 10886400.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1728000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17280000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 23167200.0, + "actual": 22240512.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4032000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 40320000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 8919400.0, + "actual": 9186982.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1442000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14420000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 28656213.0, + "actual": 29515899.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4944000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 49440000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4464000.0, + "actual": 4597920.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1030000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10300000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 19335067.0, + "actual": 19915119.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3399000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 33990000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 36855814.0, + "actual": 37961488.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6386000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 60760000.0, + "actual": 62582800.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21527000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3914000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39140000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11680200.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1854000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18540000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 25384800.0, + "actual": 26146344.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4326000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 43260000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 9574600.0, + "actual": 9478854.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1386000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13860000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 27427413.0, + "actual": 27153139.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4752000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 47520000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4176000.0, + "actual": 4134240.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 990000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9900000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 18595867.0, + "actual": 18409908.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3267000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 32670000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 35725957.0, + "actual": 35368697.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6138000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 62000000.0, + "actual": 61380000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20691000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3762000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 37620000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11226600.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1782000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17820000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 26493600.0, + "actual": 26228664.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4158000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 41580000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 10557400.0, + "actual": 10979696.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1456000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14560000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 27918933.0, + "actual": 29035690.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4992000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 49920000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4320000.0, + "actual": 4492800.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1040000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10400000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 18965467.0, + "actual": 19724086.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3432000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 34320000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 37044884.0, + "actual": 38526679.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6448000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 64480000.0, + "actual": 67059200.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21736000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3952000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39520000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11793600.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1872000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18720000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 27158880.0, + "actual": 28245235.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4368000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 43680000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 11212600.0, + "actual": 10651970.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1330000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13300000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 29885013.0, + "actual": 28390762.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4560000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 45600000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4656000.0, + "actual": 4423200.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 950000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9500000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 22291867.0, + "actual": 21177274.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3135000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 31350000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 39464930.0, + "actual": 37491684.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 5890000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 66960000.0, + "actual": 63612000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 19855000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3610000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36100000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 10773000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1710000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17100000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 27602400.0, + "actual": 26222280.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 3990000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 39900000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 11867800.0, + "actual": 12579868.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1484000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14840000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 31113813.0, + "actual": 32980642.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 5088000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 50880000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4944000.0, + "actual": 5240640.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1060000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10600000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 23031067.0, + "actual": 24412931.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3498000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 34980000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 44087216.0, + "actual": 46732449.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6572000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 69440000.0, + "actual": 73606400.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 22154000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 4028000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 40280000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 12020400.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1908000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 19080000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 28045920.0, + "actual": 29728675.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4452000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 44520000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 11540200.0, + "actual": 11309396.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1372000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13720000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 31851093.0, + "actual": 31214071.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4704000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 47040000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4464000.0, + "actual": 4374720.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 980000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9800000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 24139867.0, + "actual": 23657070.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3234000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 32340000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 49346273.0, + "actual": 48359348.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6076000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 68200000.0, + "actual": 66836000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20482000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3724000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 37240000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11113200.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1764000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17640000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 27602400.0, + "actual": 27050352.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4116000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 41160000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 10885000.0, + "actual": 10993850.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1414000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14140000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 32342613.0, + "actual": 32666039.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4848000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48480000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4656000.0, + "actual": 4702560.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1010000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10100000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 23031067.0, + "actual": 23261378.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3333000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 33330000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 51605987.0, + "actual": 52122047.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6262000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 65720000.0, + "actual": 66377200.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21109000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3838000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38380000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11453400.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1818000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18180000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 26493600.0, + "actual": 26758536.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4242000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 42420000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 9902200.0, + "actual": 9605134.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1358000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13580000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 31113813.0, + "actual": 30180399.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4656000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46560000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5136000.0, + "actual": 4981920.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 970000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9700000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 21183067.0, + "actual": 20547575.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3201000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 32010000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 48360101.0, + "actual": 46909298.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6014000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 63240000.0, + "actual": 61342800.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20273000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3686000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36860000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 10999800.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1746000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17460000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 25384800.0, + "actual": 24623256.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4074000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 40740000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 8919400.0, + "actual": 9186982.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1442000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14420000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 29885013.0, + "actual": 30781563.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4944000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 49440000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5424000.0, + "actual": 5586720.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1030000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10300000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 20443867.0, + "actual": 21057183.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3399000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 33990000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 41991600.0, + "actual": 43251348.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6386000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 58900000.0, + "actual": 60667000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21527000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3914000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39140000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11680200.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1854000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18540000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 23610720.0, + "actual": 24319042.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4326000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 43260000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 7936600.0, + "actual": 7936600.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1400000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 29393493.0, + "actual": 29393493.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4800000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5904000.0, + "actual": 5904000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 21737467.0, + "actual": 21737467.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3300000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 33000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 40578139.0, + "actual": 40578139.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6200000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 54560000.0, + "actual": 54560000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20900000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3800000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11340000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1800000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 22723680.0, + "actual": 22723680.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4200000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 42000000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 7936600.0, + "actual": 7619136.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1344000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 13440000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 31113813.0, + "actual": 29869260.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4608000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46080000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 5424000.0, + "actual": 5207040.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 960000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 9600000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 22291867.0, + "actual": 21400192.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3168000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 31680000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 41745056.0, + "actual": 40075254.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 5952000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 57660000.0, + "actual": 55353600.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 20064000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3648000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36480000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 10886400.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1728000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 17280000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 24276000.0, + "actual": 23304960.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4032000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 40320000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "CapitalCost", + "estimate": 770000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Claims", + "estimate": 8264200.0, + "actual": 8429484.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExpectedProfit", + "estimate": 700000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "ExternalCost", + "estimate": 1400000.0, + "actual": 1428000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "InternalCost", + "estimate": 1680000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "AGRICULTURE", + "amountType": "Premium", + "estimate": 14000000.0, + "actual": 14280000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Claims", + "estimate": 29885013.0, + "actual": 30482713.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4896000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMMERCIAL", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48960000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "CapitalCost", + "estimate": 550000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Claims", + "estimate": 4944000.0, + "actual": 5042880.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExpectedProfit", + "estimate": 500000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "ExternalCost", + "estimate": 1000000.0, + "actual": 1020000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "InternalCost", + "estimate": 1200000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_TECH", + "amountType": "Premium", + "estimate": 10000000.0, + "actual": 10200000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "CapitalCost", + "estimate": 1815000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Claims", + "estimate": 21183067.0, + "actual": 21606728.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExpectedProfit", + "estimate": 1650000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "ExternalCost", + "estimate": 3300000.0, + "actual": 3366000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "InternalCost", + "estimate": 3960000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "ENERGY_MINING", + "amountType": "Premium", + "estimate": 33000000.0, + "actual": 33660000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "CapitalCost", + "estimate": 3410000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Claims", + "estimate": 39998842.0, + "actual": 40798819.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExpectedProfit", + "estimate": 3100000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "ExternalCost", + "estimate": 6200000.0, + "actual": 6324000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "InternalCost", + "estimate": 7440000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOMEOWNERS", + "amountType": "Premium", + "estimate": 55800000.0, + "actual": 56916000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Claims", + "estimate": 20900000.0, + "actual": 21318000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3876000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_ANN", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38760000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "CapitalCost", + "estimate": 990000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Claims", + "estimate": 11340000.0, + "actual": 11566800.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExpectedProfit", + "estimate": 900000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "ExternalCost", + "estimate": 1800000.0, + "actual": 1836000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "InternalCost", + "estimate": 2160000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN_US", + "amountType": "Premium", + "estimate": 18000000.0, + "actual": 18360000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "CapitalCost", + "estimate": 2310000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Claims", + "estimate": 23167200.0, + "actual": 23630544.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExpectedProfit", + "estimate": 2100000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "ExternalCost", + "estimate": 4200000.0, + "actual": 4284000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "InternalCost", + "estimate": 5040000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "WORKERS_COMP", + "amountType": "Premium", + "estimate": 42000000.0, + "actual": 42840000.0 + } + ] } } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json index 3217b529e..3b89ad029 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json @@ -2,7 +2,7 @@ "id": "AGRICULTURE", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Agriculture", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "Crop insurance, livestock coverage, and agricultural risk management for North and South American farming operations", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json index 69f9de8ef..27edc8f4c 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json @@ -2,7 +2,7 @@ "id": "COMMERCIAL", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Commercial Lines", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "Multi-peril commercial package policies covering property, liability, and inland marine risks for businesses", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json index 0cc1a4168..e685fe5c7 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json @@ -2,7 +2,7 @@ "id": "CYBER_TECH", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Cyber & Technology", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "Standalone cyber liability and technology errors & omissions insurance for US and Americas markets", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json index d2f573dc9..6fdc861e3 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json @@ -2,7 +2,7 @@ "id": "ENERGY_MINING", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Energy & Mining", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "Upstream and downstream energy, mining operations, and renewable energy project insurance", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json index b6b5dcd96..35dd5f2b4 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json @@ -2,7 +2,7 @@ "id": "HOMEOWNERS", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Homeowners", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "Residential property insurance covering homes, condos, and personal property in the Americas", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json index 135252e3b..fac515c3c 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json @@ -2,7 +2,7 @@ "id": "LIFE_ANN", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Life & Annuity", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "Individual and group life insurance, annuities, and retirement products for the Americas market", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json index c29fc28ef..52439400c 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json @@ -2,7 +2,7 @@ "id": "SPECIALTY_AVTN_US", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Specialty & Aviation", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "US specialty lines including aviation, space, political risk, and surety for Americas operations", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json index 99a59b46f..f328ec06b 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json @@ -2,7 +2,7 @@ "id": "WORKERS_COMP", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Workers Compensation", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/AmericasIns/LineOfBusiness", "category": "Lines of Business", "description": "Statutory workers compensation and employers liability insurance across US states and territories", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs new file mode 100644 index 000000000..168782e97 --- /dev/null +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs @@ -0,0 +1,7 @@ +// +// Id: ExternalDependencies +// DisplayName: External Dependencies +// + +@@FutuRe/LineOfBusiness/_Source/LineOfBusinessLayoutAreas +@@FutuRe/LineOfBusiness/_Source/LineOfBusiness diff --git a/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json b/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json index 21e73c4f5..df0d14afa 100644 --- a/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json +++ b/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json @@ -12,6 +12,7784 @@ "$type": "AnalysisContent", "id": "Analysis", "name": "AsiaRe Profitability Analysis", - "description": "Interactive profitability analysis for AsiaRe with local lines of business, estimates vs actuals, and quarterly trends." + "description": "Interactive profitability analysis for AsiaRe with local lines of business, estimates vs actuals, and quarterly trends.", + "datacube": [ + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2449442168.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 414330739.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4223423702.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 740820742.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 151590295.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1483392644.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5486579879.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 776345941.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7922360025.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1244238708.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 180057837.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1766145400.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3283070350.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 454046880.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4414776475.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1872000000.0, + "actual": 1925888737.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 241285426.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2404314382.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1120950485.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 213853323.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2125992158.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 5814000000.0, + "actual": 6377621052.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 558217399.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5745175782.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2512257460.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 409737195.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4276811796.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 747215676.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 150933534.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1475802983.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5775373897.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 781695475.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7895824021.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1260356265.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 180562039.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1834064335.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3394873662.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 459766086.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4559292840.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1601130565.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 233459871.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2407425806.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1147089448.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 204705379.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2077143455.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3791038523.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 562406697.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5639076322.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2517950167.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 416728560.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4222794987.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 713777923.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 153929891.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1482570422.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5721190378.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 764609289.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7846187040.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1238670971.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 178698119.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1816497129.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3400595936.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 451537643.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4588114203.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1618387920.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 243974399.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2417722968.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1123316063.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 207674708.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2077240038.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3825141560.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 585147512.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5647044920.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2507839061.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 423917054.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4263229761.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 751077941.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 149629667.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1493737914.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5558324807.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 782872029.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7726642612.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1281126268.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 184296487.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1782917396.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3288527050.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 463433515.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4481892091.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1524545495.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 233478476.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2400914524.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1178326014.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 213680200.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2067210527.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3779418671.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 565951380.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5682252472.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2551069452.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 431871175.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4283348392.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 699061307.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 151986496.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1521646782.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 14040000000.0, + "actual": 15928556084.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 769087419.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7856693635.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1233444459.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 179295465.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1810149249.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3484196563.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 460148029.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4491670267.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1575673147.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 235372587.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2377285349.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1200785916.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 207460404.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2134660739.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3948549483.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 558127103.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5731680485.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2553138812.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 427021387.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4244101814.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 698432941.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 148417405.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1501821220.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5864945426.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 797724184.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7650076744.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1253197424.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 175225592.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1823879918.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3482367332.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 438812643.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4568041728.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1521837722.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 243752671.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2398655084.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1132213371.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 209688558.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2122330092.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3841908760.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 582737210.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5711355219.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2487098518.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 420990261.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4187087174.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 709986301.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 148305447.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1513795864.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5739497214.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 777103084.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7954486599.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1234397223.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 177026731.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1801265461.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3386825443.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 442713098.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4470855401.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1522059937.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 241887883.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2373140869.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1204010809.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 214531406.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2077231110.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3833520477.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 575779040.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5602155476.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2471074069.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 430974959.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4151991784.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 725625851.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 152561575.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1504262586.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5533067366.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 761136362.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7895939063.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1264896725.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 179643866.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1795035685.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3409484315.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 463072461.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4541233653.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1563447136.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 237685958.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2361448116.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1143325845.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 206096632.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2130380493.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3890537059.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 562426244.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5688283889.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2630530345.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 418566895.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4157967483.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 730098738.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 145955295.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1521680946.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5823130473.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 801949025.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7955776130.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1307748530.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 176396160.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1830698423.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3287042281.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 447328088.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4497415403.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1560495845.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 246988447.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2357628998.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1192798124.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 209433105.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2080277057.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 4056565054.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 586943456.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5682445707.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2589231108.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 411300880.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4209369078.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 754197659.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 150712623.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1487802470.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5783570460.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 759275335.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7813164903.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1272887319.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 183809375.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1806060787.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3486051500.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 438663010.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4438337891.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1587460381.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 242523061.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2369839196.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1131427523.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 214917620.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2077757127.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3944068499.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 574082848.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5642137099.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2562068334.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 420574124.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4186429786.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 710165330.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 151945726.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1526082375.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5625338665.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 788035102.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7718470017.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1254070661.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 182720137.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1785599790.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3352187263.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 463458270.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4423057761.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1872000000.0, + "actual": 1902928672.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 235869422.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2447625259.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1206583167.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 214798889.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2080276835.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 5814000000.0, + "actual": 6005169587.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 558294942.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5786473615.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2586233649.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 422814280.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4256069152.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 736069036.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 145570408.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1529233984.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5582024886.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 787646592.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7898936490.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1235736544.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 175846630.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1831602960.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3377478778.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 443853402.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4429266476.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1872000000.0, + "actual": 2003447501.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 235731801.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2410063663.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1144742113.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 209855501.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2111275989.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 5814000000.0, + "actual": 6837535727.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 556056608.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5792416720.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2500178733.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 407489351.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4187160730.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 735097731.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 147857597.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1516267153.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5695378980.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 776615748.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7875264043.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1229784581.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 184137549.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1764696218.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3375445253.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 459034066.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4572707143.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1872000000.0, + "actual": 1914602631.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 234635215.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2407920918.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1203415890.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 213731141.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2083893701.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 5814000000.0, + "actual": 6663456610.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 560084618.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5782240189.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2465123194.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 427058929.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4157920996.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 721807338.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 151085954.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1523048082.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5865296943.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 797063547.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7692220642.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1303925789.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 184119295.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1834286834.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3426320775.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 445469008.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4414461545.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1613318945.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 245242522.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2441358325.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1145002848.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 213620919.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2126102943.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 4030161476.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 582263889.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5610645803.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2609023860.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 418999642.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4153368865.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 744211901.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 147548359.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1488311452.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5534289351.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 771962659.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7651383304.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1319662422.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 177614550.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1826233412.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3336574322.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 462991042.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4525466713.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1630416795.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 234460921.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2403476710.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1136849666.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 215827932.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2139513651.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3793333462.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 567762081.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5646526331.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2507637347.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 422676463.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4238395570.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 720587257.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 150689292.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1500685384.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5765963052.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 756679152.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7723473422.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1276475961.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 182369844.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1830641412.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3408755434.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 446333980.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4543551014.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1596096863.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 237554881.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2358717486.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1198706612.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 212768904.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2084368914.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3855622988.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 566867037.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5654473477.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2504004089.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 410607653.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4183603265.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 752564947.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 151595862.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1495226780.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5724058541.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 770684454.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7925675330.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1222240919.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 177698668.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1803451479.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3384607946.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 454177052.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4487379867.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1568381543.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 235877300.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2396638866.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1203619108.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 213729912.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2097747640.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3786013400.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 570528459.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5624689638.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "CapitalCost", + "estimate": 231000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Claims", + "estimate": 2520000000.0, + "actual": 2511973952.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExpectedProfit", + "estimate": 210000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "ExternalCost", + "estimate": 420000000.0, + "actual": 428024271.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "InternalCost", + "estimate": 504000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CONSTRUCTION_ENG", + "amountType": "Premium", + "estimate": 4200000000.0, + "actual": 4222334064.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "CapitalCost", + "estimate": 82500000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Claims", + "estimate": 720000000.0, + "actual": 737153031.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExpectedProfit", + "estimate": 75000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "ExternalCost", + "estimate": 150000000.0, + "actual": 147521766.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "InternalCost", + "estimate": 180000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "CYBER_DIGITAL", + "amountType": "Premium", + "estimate": 1500000000.0, + "actual": 1515068288.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "CapitalCost", + "estimate": 429000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Claims", + "estimate": 5616000000.0, + "actual": 5458493838.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExpectedProfit", + "estimate": 390000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "ExternalCost", + "estimate": 780000000.0, + "actual": 768058631.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "InternalCost", + "estimate": 936000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "EARTHQUAKE_VOLCANIC", + "amountType": "Premium", + "estimate": 7800000000.0, + "actual": 7706128539.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "CapitalCost", + "estimate": 99000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Claims", + "estimate": 1260000000.0, + "actual": 1307853560.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExpectedProfit", + "estimate": 90000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "ExternalCost", + "estimate": 180000000.0, + "actual": 175386545.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "InternalCost", + "estimate": 216000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MICRO_HEALTH_PA", + "amountType": "Premium", + "estimate": 1800000000.0, + "actual": 1798209817.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "CapitalCost", + "estimate": 247500000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Claims", + "estimate": 3330000000.0, + "actual": 3397869497.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExpectedProfit", + "estimate": 225000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "ExternalCost", + "estimate": 450000000.0, + "actual": 441749751.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "InternalCost", + "estimate": 540000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR_TPL", + "amountType": "Premium", + "estimate": 4500000000.0, + "actual": 4484599382.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "CapitalCost", + "estimate": 132000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Claims", + "estimate": 1560000000.0, + "actual": 1574898271.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExpectedProfit", + "estimate": 120000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "ExternalCost", + "estimate": 240000000.0, + "actual": 236313376.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "InternalCost", + "estimate": 288000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "PADDY_CROP", + "amountType": "Premium", + "estimate": 2400000000.0, + "actual": 2418850008.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "CapitalCost", + "estimate": 115500000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Claims", + "estimate": 1155000000.0, + "actual": 1120862341.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExpectedProfit", + "estimate": 105000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "ExternalCost", + "estimate": 210000000.0, + "actual": 213162152.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "InternalCost", + "estimate": 252000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRADE_CREDIT", + "amountType": "Premium", + "estimate": 2100000000.0, + "actual": 2113108873.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "CapitalCost", + "estimate": 313500000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Claims", + "estimate": 3876000000.0, + "actual": 3792770589.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExpectedProfit", + "estimate": 285000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "ExternalCost", + "estimate": 570000000.0, + "actual": 567440000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "InternalCost", + "estimate": 684000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TYPHOON_FLOOD", + "amountType": "Premium", + "estimate": 5700000000.0, + "actual": 5761570531.0 + } + ] } } diff --git a/samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs b/samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs new file mode 100644 index 000000000..168782e97 --- /dev/null +++ b/samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs @@ -0,0 +1,7 @@ +// +// Id: ExternalDependencies +// DisplayName: External Dependencies +// + +@@FutuRe/LineOfBusiness/_Source/LineOfBusinessLayoutAreas +@@FutuRe/LineOfBusiness/_Source/LineOfBusiness diff --git a/samples/Graph/Data/FutuRe/DataDistribution.md b/samples/Graph/Data/FutuRe/DataDistribution.md index d27a707d6..788b08497 100644 --- a/samples/Graph/Data/FutuRe/DataDistribution.md +++ b/samples/Graph/Data/FutuRe/DataDistribution.md @@ -19,42 +19,35 @@ Each business unit owns its data. The group hub doesn't store copies — it read ```mermaid graph LR subgraph EuropeRe Domain - EU_CSV[Datacube EUR amounts] - EU_SVC[IContentService] + EU_NODE[Analysis Node
EUR datacube] end subgraph AmericasIns Domain - AM_CSV[Datacube USD amounts] - AM_SVC[IContentService] + AM_NODE[Analysis Node
USD datacube] end subgraph AsiaRe Domain - AS_CSV[Datacube JPY amounts] - AS_SVC[IContentService] + AS_NODE[Analysis Node
JPY datacube] end - EU_CSV --> EU_SVC - AM_CSV --> AM_SVC - AS_CSV --> AS_SVC - subgraph Group Hub PART[PartitionedHubDataSource] MAP[TransactionMapping + FX Conversion] AGG[Consolidated View] end - EU_SVC --> PART - AM_SVC --> PART - AS_SVC --> PART + EU_NODE --> PART + AM_NODE --> PART + AS_NODE --> PART PART --> MAP --> AGG classDef eu fill:#e8f0fe,stroke:#4285f4,color:#333 classDef am fill:#fce8e6,stroke:#ea4335,color:#333 classDef asia fill:#fef7e0,stroke:#fbbc04,color:#333 classDef hub fill:#e6f4ea,stroke:#34a853,color:#333 - class EU_CSV,EU_SVC eu - class AM_CSV,AM_SVC am - class AS_CSV,AS_SVC asia + class EU_NODE eu + class AM_NODE am + class AS_NODE asia class PART,MAP,AGG hub ``` @@ -99,12 +92,11 @@ Here's what actually happens when the group dashboard loads. No manual orchestra ```mermaid graph TD - CSV[BU Data] - CONTENT[IContentService reads raw bytes] - PARSE[LoadLocalDataCube parses data] + NODE[BU Analysis Node
embedded datacube] + PARSE[LoadLocalDataCube reads from node content] ENRICH[CombineLatest enriches with LoB names] - CSV --> CONTENT --> PARSE --> ENRICH + NODE --> PARSE --> ENRICH ENRICH --> PHDS[PartitionedHubDataSource merges BU streams] @@ -124,7 +116,7 @@ graph TD classDef process fill:#fff3e0,stroke:#f57c00,color:#333 classDef ref fill:#f3e8fd,stroke:#9c27b0,color:#333 classDef output fill:#e6f4ea,stroke:#34a853,color:#333 - class CSV,CONTENT data + class NODE data class PARSE,ENRICH,PHDS,COMBINE,AGG process class MAPPINGS,FX,LOBS ref class CHARTS output @@ -134,7 +126,7 @@ graph TD ## Key Design Decisions -**Domain ownership** — each BU manages its own data. EuropeRe's actuary updates their data directly; the group never touches it. +**BU data ownership** — each BU's Analysis node embeds its own datacube as structured content within the MeshNode. EuropeRe's actuary updates their data directly; the group hub never touches it. This works identically across deployment modes — filesystem, PostgreSQL, or Cosmos DB — because MeshNodes are the universal storage unit. **Stream composition over data copying** — `PartitionedHubDataSource` reads from BU hubs as live `IObservable` streams. When EuropeRe's data changes, the group view updates automatically — no rebuild, no re-import. @@ -148,7 +140,9 @@ graph TD ) ``` -**No intermediate state** — there are no staging tables, no materialized views, no cache invalidation problems. The only persistent storage is the BU's own data and the mapping rule definitions. +**No intermediate state** — there are no staging tables, no materialized views, no cache invalidation problems. The only persistent storage is the BU's own data (embedded in its Analysis node) and the mapping rule definitions. + +**Deployment-mode independence** — datacube data is embedded in MeshNode content, not in external files. This means the same FutuRe configuration works in monolith mode (filesystem), distributed mode (PostgreSQL/Azure), and test mode — no special file system setup required. --- diff --git a/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json b/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json index a005c1b36..97338b496 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json @@ -12,6 +12,7784 @@ "$type": "AnalysisContent", "id": "Analysis", "name": "EuropeRe Profitability Analysis", - "description": "Interactive profitability analysis for EuropeRe with local lines of business, estimates vs actuals, and quarterly trends." + "description": "Interactive profitability analysis for EuropeRe with local lines of business, estimates vs actuals, and quarterly trends.", + "datacube": [ + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 30760000.0, + "actual": 31375200.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4590000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 45900000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 56568065.0, + "actual": 57699426.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7650000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 78750000.0, + "actual": 80325000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 24418800.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3876000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38760000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 28396800.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4896000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48960000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 40577778.0, + "actual": 41389334.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5610000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 56100000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 16065000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2550000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 25500000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 15273244.0, + "actual": 15578709.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3264000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 32640000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 14774222.0, + "actual": 15069706.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2244000.0 + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-09", + "quarter": "Q3-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22440000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 27250000.0, + "actual": 26432500.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4365000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 43650000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 52717205.0, + "actual": 51135689.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7275000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 75000000.0, + "actual": 72750000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 23221800.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3686000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36860000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 27004800.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4656000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46560000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 39081778.0, + "actual": 37909325.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5335000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 53350000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15277500.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2425000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 24250000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 16860444.0, + "actual": 16354631.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3104000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 31040000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 15390222.0, + "actual": 14928515.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2134000.0 + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-10", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 21340000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 26080000.0, + "actual": 27384000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4725000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 47250000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 47246345.0, + "actual": 49608662.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7875000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 71250000.0, + "actual": 74812500.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 25137000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3990000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39900000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 29232000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 5040000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 50400000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 37585778.0, + "actual": 39465067.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5775000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 57750000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 16537500.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2625000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 26250000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 17654044.0, + "actual": 18536746.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3360000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 33600000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 16006222.0, + "actual": 16806533.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2310000.0 + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-11", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 23100000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 28420000.0, + "actual": 27851600.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4410000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 44100000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 48255484.0, + "actual": 47290374.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7350000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 67500000.0, + "actual": 66150000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 23461200.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3724000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 37240000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 27283200.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4704000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 47040000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 36089778.0, + "actual": 35367982.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5390000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 53900000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15435000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2450000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 24500000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 20034844.0, + "actual": 19634147.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3136000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 31360000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 16622222.0, + "actual": 16289778.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2156000.0 + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2024-12", + "quarter": "Q4-2024", + "year": 2024, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 21560000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 28420000.0, + "actual": 28704200.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4545000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 45450000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 48866345.0, + "actual": 49355008.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7575000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 71250000.0, + "actual": 71962500.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 24179400.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3838000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38380000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 28118400.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4848000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48480000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 36089778.0, + "actual": 36450676.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5555000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 55550000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15907500.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2525000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 25250000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 18447644.0, + "actual": 18632120.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3232000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 32320000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 15390222.0, + "actual": 15544124.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2222000.0 + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-01", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22220000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 27250000.0, + "actual": 26160000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4320000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 43200000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 46879829.0, + "actual": 45004636.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7200000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 69000000.0, + "actual": 66240000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 22982400.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3648000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36480000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 26726400.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4608000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46080000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 34593778.0, + "actual": 33210027.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5280000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 52800000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15120000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2400000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 24000000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 16860444.0, + "actual": 16186026.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3072000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 30720000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 14774222.0, + "actual": 14183253.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2112000.0 + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-02", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 21120000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 24910000.0, + "actual": 25657300.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4635000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 46350000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 42997205.0, + "actual": 44287121.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7725000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 75000000.0, + "actual": 77250000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 24658200.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3914000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39140000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 28675200.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4944000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 49440000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 37585778.0, + "actual": 38713351.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5665000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 56650000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 16222500.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2575000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 25750000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 15273244.0, + "actual": 15731441.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3296000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 32960000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 13542222.0, + "actual": 13948489.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2266000.0 + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-03", + "quarter": "Q1-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22660000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 23740000.0, + "actual": 23502600.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4455000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 44550000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 41621549.0, + "actual": 41205334.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7425000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 76500000.0, + "actual": 75735000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 23700600.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3762000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 37620000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 27561600.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4752000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 47520000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 39081778.0, + "actual": 38690960.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5445000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 54450000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15592500.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2475000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 24750000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 13686044.0, + "actual": 13549184.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3168000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 31680000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 12926222.0, + "actual": 12796960.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2178000.0 + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-04", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 21780000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 24910000.0, + "actual": 25906400.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4680000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 46800000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 40368065.0, + "actual": 41982788.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7800000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 78750000.0, + "actual": 81900000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 24897600.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3952000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39520000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 28953600.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4992000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 49920000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 40577778.0, + "actual": 42200889.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5720000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 57200000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 16380000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2600000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 26000000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 14479644.0, + "actual": 15058830.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3328000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 33280000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 12310222.0, + "actual": 12802631.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2288000.0 + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-05", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22880000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 29590000.0, + "actual": 28110500.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4275000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 42750000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 42354581.0, + "actual": 40236852.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7125000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 81000000.0, + "actual": 76950000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 22743000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3610000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36100000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 26448000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4560000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 45600000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 42073778.0, + "actual": 39970089.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5225000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 52250000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 14962500.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2375000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 23750000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 15273244.0, + "actual": 14509582.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3040000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 30400000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 12926222.0, + "actual": 12279911.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2090000.0 + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-06", + "quarter": "Q2-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 20900000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 30760000.0, + "actual": 32605600.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4770000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 47700000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 47458925.0, + "actual": 50306460.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7950000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 82500000.0, + "actual": 87450000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 25376400.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 4028000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 40280000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 29510400.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 5088000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 50880000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 43569778.0, + "actual": 46183965.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5830000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 58300000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 16695000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2650000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 26500000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 16066844.0, + "actual": 17030855.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3392000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 33920000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 13542222.0, + "actual": 14354755.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2332000.0 + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-07", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 23320000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 31930000.0, + "actual": 31291400.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4410000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 44100000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 52074581.0, + "actual": 51033089.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7350000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 81000000.0, + "actual": 79380000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 23461200.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3724000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 37240000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 27283200.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4704000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 47040000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 42073778.0, + "actual": 41232302.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5390000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 53900000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15435000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2450000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 24500000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 14479644.0, + "actual": 14190051.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3136000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 31360000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 14158222.0, + "actual": 13875058.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2156000.0 + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-08", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 21560000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 30760000.0, + "actual": 31067600.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4545000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 45450000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 56568065.0, + "actual": 57133746.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7575000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 78750000.0, + "actual": 79537500.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 24179400.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3838000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38380000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 28118400.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4848000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48480000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 40577778.0, + "actual": 40983556.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5555000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 55550000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15907500.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2525000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 25250000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 15273244.0, + "actual": 15425976.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3232000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 32320000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 14774222.0, + "actual": 14921964.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2222000.0 + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-09", + "quarter": "Q3-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22220000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 27250000.0, + "actual": 26432500.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4365000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 43650000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 52717205.0, + "actual": 51135689.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7275000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 75000000.0, + "actual": 72750000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 23221800.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3686000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36860000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 27004800.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4656000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46560000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 39081778.0, + "actual": 37909325.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5335000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 53350000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15277500.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2425000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 24250000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 16860444.0, + "actual": 16354631.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3104000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 31040000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 15390222.0, + "actual": 14928515.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2134000.0 + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-10", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 21340000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 26080000.0, + "actual": 26862400.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4635000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 46350000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 47246345.0, + "actual": 48663735.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7725000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 71250000.0, + "actual": 73387500.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 24658200.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3914000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 39140000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 28675200.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4944000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 49440000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 37585778.0, + "actual": 38713351.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5665000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 56650000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 16222500.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2575000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 25750000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 17654044.0, + "actual": 18183665.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3296000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 32960000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 16006222.0, + "actual": 16486409.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2266000.0 + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-11", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22660000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 28420000.0, + "actual": 28420000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4500000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 45000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 48255484.0, + "actual": 48255484.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7500000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 67500000.0, + "actual": 67500000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 23940000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3800000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 27840000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4800000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 36089778.0, + "actual": 36089778.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5500000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 55000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15750000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2500000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 25000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 20034844.0, + "actual": 20034844.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3200000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 32000000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 16622222.0, + "actual": 16622222.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2200000.0 + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2025-12", + "quarter": "Q4-2025", + "year": 2025, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22000000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 28420000.0, + "actual": 27283200.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4320000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 43200000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 48866345.0, + "actual": 46911691.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7200000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 71250000.0, + "actual": 68400000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 22982400.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3648000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 36480000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 26726400.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4608000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 46080000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 36089778.0, + "actual": 34646187.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5280000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 52800000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 15120000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2400000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 24000000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 18447644.0, + "actual": 17709738.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3072000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 30720000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 15390222.0, + "actual": 14774613.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2112000.0 + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2026-01", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 21120000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "CapitalCost", + "estimate": 2475000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Claims", + "estimate": 27250000.0, + "actual": 27795000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExpectedProfit", + "estimate": 2250000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "ExternalCost", + "estimate": 4500000.0, + "actual": 4590000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "InternalCost", + "estimate": 5400000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "COMM_FIRE", + "amountType": "Premium", + "estimate": 45000000.0, + "actual": 45900000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "CapitalCost", + "estimate": 4125000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Claims", + "estimate": 46879829.0, + "actual": 47817426.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExpectedProfit", + "estimate": 3750000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "ExternalCost", + "estimate": 7500000.0, + "actual": 7650000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "InternalCost", + "estimate": 9000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "HOUSEHOLD", + "amountType": "Premium", + "estimate": 69000000.0, + "actual": 70380000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "CapitalCost", + "estimate": 2090000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "Claims", + "estimate": 23940000.0, + "actual": 24418800.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "ExpectedProfit", + "estimate": 1900000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "ExternalCost", + "estimate": 3800000.0, + "actual": 3876000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "InternalCost", + "estimate": 4560000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIABILITY", + "amountType": "Premium", + "estimate": 38000000.0, + "actual": 38760000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "CapitalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Claims", + "estimate": 27840000.0, + "actual": 28396800.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExpectedProfit", + "estimate": 2400000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "ExternalCost", + "estimate": 4800000.0, + "actual": 4896000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "InternalCost", + "estimate": 5760000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "LIFE_HEALTH_EU", + "amountType": "Premium", + "estimate": 48000000.0, + "actual": 48960000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "CapitalCost", + "estimate": 3025000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "Claims", + "estimate": 34593778.0, + "actual": 35285654.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "ExpectedProfit", + "estimate": 2750000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "ExternalCost", + "estimate": 5500000.0, + "actual": 5610000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "InternalCost", + "estimate": 6600000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "MOTOR", + "amountType": "Premium", + "estimate": 55000000.0, + "actual": 56100000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "CapitalCost", + "estimate": 1375000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Claims", + "estimate": 15750000.0, + "actual": 16065000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExpectedProfit", + "estimate": 1250000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "ExternalCost", + "estimate": 2500000.0, + "actual": 2550000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "InternalCost", + "estimate": 3000000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "SPECIALTY_AVTN", + "amountType": "Premium", + "estimate": 25000000.0, + "actual": 25500000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "CapitalCost", + "estimate": 1760000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "Claims", + "estimate": 16860444.0, + "actual": 17197653.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExpectedProfit", + "estimate": 1600000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "ExternalCost", + "estimate": 3200000.0, + "actual": 3264000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "InternalCost", + "estimate": 3840000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TECH_RISK", + "amountType": "Premium", + "estimate": 32000000.0, + "actual": 32640000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "CapitalCost", + "estimate": 1210000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "Claims", + "estimate": 14774222.0, + "actual": 15069706.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExpectedProfit", + "estimate": 1100000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "ExternalCost", + "estimate": 2200000.0, + "actual": 2244000.0 + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "InternalCost", + "estimate": 2640000.0, + "actual": null + }, + { + "month": "2026-02", + "quarter": "Q1-2026", + "year": 2026, + "lineOfBusiness": "TRANSPORT", + "amountType": "Premium", + "estimate": 22000000.0, + "actual": 22440000.0 + } + ] } } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json index e3fc6e965..976cd24d0 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json @@ -2,7 +2,7 @@ "id": "COMM_FIRE", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Commercial Fire", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "Commercial and industrial property insurance including engineering risks", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json index 2a9a46c68..58be656b6 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json @@ -2,7 +2,7 @@ "id": "HOUSEHOLD", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Household", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "Residential property, home contents, and personal liability coverage bundled for European households", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json index b34d5f050..c335b9209 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json @@ -2,7 +2,7 @@ "id": "LIABILITY", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Liability", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "General, products, and employers liability combined with professional indemnity", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json index 66a9caeba..1492ddaf7 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json @@ -2,7 +2,7 @@ "id": "LIFE_HEALTH_EU", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Life & Health", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "Life, disability, and health reinsurance for European social security supplement markets", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json index bbd2eb015..7f0e2aeb0 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json @@ -2,7 +2,7 @@ "id": "MOTOR", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Motor", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "Private and commercial motor vehicle insurance across European markets", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json index b860f7fe6..c34972a3c 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json @@ -2,7 +2,7 @@ "id": "SPECIALTY_AVTN", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Specialty & Aviation", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "Combined specialty lines and aviation risks for European and global programs", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json index 2dfe9763b..6fd44e836 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json @@ -2,7 +2,7 @@ "id": "TECH_RISK", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Technology Risk", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "Combined cyber insurance and technology professional liability for digital economy risks", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json index 18ddb05b8..76c3af574 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json @@ -2,7 +2,7 @@ "id": "TRANSPORT", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Transport", - "nodeType": "FutuRe/LineOfBusiness", + "nodeType": "FutuRe/EuropeRe/LineOfBusiness", "category": "Lines of Business", "description": "Marine cargo, hull, and inland transit insurance for European trade routes", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs new file mode 100644 index 000000000..168782e97 --- /dev/null +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs @@ -0,0 +1,7 @@ +// +// Id: ExternalDependencies +// DisplayName: External Dependencies +// + +@@FutuRe/LineOfBusiness/_Source/LineOfBusinessLayoutAreas +@@FutuRe/LineOfBusiness/_Source/LineOfBusiness diff --git a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs index 355d93f32..d6277f662 100644 --- a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs +++ b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs @@ -29,4 +29,27 @@ public record AnalysisContent /// Brief description of this analysis scope. ///
public string? Description { get; init; } + + /// + /// Embedded datacube rows for this analysis instance. + /// Each BU's Analysis node stores its own datacube data here, + /// enabling deployment-mode-independent data loading (no CSV/filesystem dependency). + /// + public DataCubeRow[]? Datacube { get; init; } +} + +/// +/// Raw datacube row as stored in MeshNode content. +/// Contains only the base data fields; runtime-derived fields +/// (Id, BusinessUnit, Currency, display names) are added during loading. +/// +public record DataCubeRow +{ + public string Month { get; init; } = string.Empty; + public string Quarter { get; init; } = string.Empty; + public int Year { get; init; } + public string LineOfBusiness { get; init; } = string.Empty; + public string AmountType { get; init; } = string.Empty; + public double Estimate { get; init; } + public double? Actual { get; init; } } diff --git a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs index aa095d8f2..55a2cd1d3 100644 --- a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs +++ b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs @@ -4,11 +4,8 @@ // using System.Collections.Immutable; -using System.Globalization; -using System.IO; using System.Reactive.Linq; using System.Text.Json; -using MeshWeaver.ContentCollections; using MeshWeaver.Data; using MeshWeaver.Mesh; using MeshWeaver.Mesh.Services; @@ -16,23 +13,22 @@ /// /// Loads profitability data for the FutuRe sample. -/// Local hubs read CSV via IContentService; the group hub aggregates -/// from local hubs applying transaction mapping rules. +/// Local hubs read datacube from their Analysis node's embedded content; +/// the group hub aggregates from local hubs applying transaction mapping rules. /// public static class FutuReDataLoader { // --------------------------------------------------------------- - // Local Data Cube: CSV + Local LoB Enrichment + // Local Data Cube: MeshNode Content + Local LoB Enrichment // --------------------------------------------------------------- /// /// Loads the local data cube for a business unit hub. - /// Reads datacube.csv from "attachments" and enriches with - /// local LoB display names from mesh queries. + /// Reads datacube from the Analysis node's embedded content and enriches + /// with local LoB display names from mesh queries. /// public static IObservable> LoadLocalDataCube(IWorkspace workspace) { - var contentService = workspace.Hub.ServiceProvider.GetRequiredService(); var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); var address = workspace.Hub.Address.ToString(); var segments = address.Split('/'); @@ -51,75 +47,80 @@ public static IObservable> LoadLocalDataCube(IWorksp && val.ValueKind == JsonValueKind.String) buCurrency = val.GetString() ?? "CHF"; - // GetContentAsync throws if the "attachments" collection isn't configured; - // treat that the same as a missing file — return an empty data cube. - Stream? stream; - try - { - stream = await contentService.GetContentAsync("attachments", "datacube.csv", ct); - } - catch - { - stream = null; - } - if (stream == null) - return (new List(), buCurrency); - using var reader = new StreamReader(stream); - var content = await reader.ReadToEndAsync(ct); - return (ParseLocalCsvContent(content, businessUnit), buCurrency); + // Read datacube from the Analysis node's embedded content + var analysisNode = await meshQuery.QueryAsync($"path:{address}", ct: ct).FirstOrDefaultAsync(ct); + var rows = ParseDatacubeFromContent(analysisNode, businessUnit); + + return (rows, buCurrency); }).CombineLatest( LoadLocalLinesOfBusiness(workspace), - (csvResult, lobs) => + (result, lobs) => { var lobLookup = lobs.ToDictionary(l => l.SystemName, l => l.DisplayName); - return csvResult.Rows.Select(row => row with + return result.Rows.Select(row => row with { LineOfBusinessName = lobLookup.GetValueOrDefault(row.LineOfBusiness, row.LineOfBusiness), LocalLineOfBusinessName = lobLookup.GetValueOrDefault(row.LocalLineOfBusiness, row.LocalLineOfBusiness), - Currency = csvResult.Currency + Currency = result.Currency }).AsEnumerable(); } ).DistinctUntilChanged(); } /// - /// Parses local CSV content into FutuReDataCube rows. - /// Local CSV columns: Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual + /// Parses datacube rows from a MeshNode's embedded content. + /// Handles both typed AnalysisContent and raw JsonElement content. /// - private static List ParseLocalCsvContent(string content, string businessUnit) + internal static List ParseDatacubeFromContent(MeshNode? node, string businessUnit) { - var rows = new List(); - var lines = content.Split('\n'); - - foreach (var rawLine in lines.Skip(1)) + if (node?.Content is AnalysisContent content && content.Datacube != null) { - var line = rawLine.TrimEnd('\r'); - if (string.IsNullOrWhiteSpace(line)) continue; - var parts = SplitCsvLine(line); - if (parts.Length < 6) continue; - - var month = parts[0]; - var lineOfBusiness = parts[3]; - var amountType = parts[4]; - - rows.Add(new FutuReDataCube + return content.Datacube.Select(row => new FutuReDataCube { - Id = $"{month}-{lineOfBusiness}-{amountType}-{businessUnit}", - Month = month, - Quarter = parts[1], - Year = int.Parse(parts[2], CultureInfo.InvariantCulture), - LineOfBusiness = lineOfBusiness, - LocalLineOfBusiness = lineOfBusiness, - AmountType = amountType, + Id = $"{row.Month}-{row.LineOfBusiness}-{row.AmountType}-{businessUnit}", + Month = row.Month, + Quarter = row.Quarter, + Year = row.Year, + LineOfBusiness = row.LineOfBusiness, + LocalLineOfBusiness = row.LineOfBusiness, + AmountType = row.AmountType, BusinessUnit = businessUnit, - Estimate = double.Parse(parts[5], CultureInfo.InvariantCulture), - Actual = parts.Length > 6 && !string.IsNullOrWhiteSpace(parts[6]) - ? double.Parse(parts[6], CultureInfo.InvariantCulture) - : null - }); + Estimate = row.Estimate, + Actual = row.Actual + }).ToList(); + } + + if (node?.Content is JsonElement json + && json.TryGetProperty("datacube", out var datacubeJson) + && datacubeJson.ValueKind == JsonValueKind.Array) + { + var rows = new List(); + foreach (var item in datacubeJson.EnumerateArray()) + { + var month = GetString(item, "month") ?? ""; + var lob = GetString(item, "lineOfBusiness") ?? ""; + var amountType = GetString(item, "amountType") ?? ""; + rows.Add(new FutuReDataCube + { + Id = $"{month}-{lob}-{amountType}-{businessUnit}", + Month = month, + Quarter = GetString(item, "quarter") ?? "", + Year = GetInt(item, "year"), + LineOfBusiness = lob, + LocalLineOfBusiness = lob, + AmountType = amountType, + BusinessUnit = businessUnit, + Estimate = GetDouble(item, "estimate"), + Actual = item.TryGetProperty("actual", out var actualVal) + && actualVal.ValueKind == JsonValueKind.Number + ? actualVal.GetDouble() + : null + }); + } + return rows; } - return rows; + return new List(); } // --------------------------------------------------------------- @@ -203,28 +204,6 @@ public static IEnumerable AggregateToGroupLevel( }); } - private static string[] SplitCsvLine(string line) - { - var parts = new List(); - var current = new System.Text.StringBuilder(); - bool inQuotes = false; - - foreach (char c in line) - { - if (c == '"') - inQuotes = !inQuotes; - else if (c == ',' && !inQuotes) - { - parts.Add(current.ToString()); - current.Clear(); - } - else - current.Append(c); - } - parts.Add(current.ToString()); - return parts.ToArray(); - } - // --------------------------------------------------------------- // Local LoB Loading (from BU namespace) // --------------------------------------------------------------- diff --git a/samples/Graph/Data/FutuRe/WhyDataMesh.md b/samples/Graph/Data/FutuRe/WhyDataMesh.md index fa232f10e..ece35abb0 100644 --- a/samples/Graph/Data/FutuRe/WhyDataMesh.md +++ b/samples/Graph/Data/FutuRe/WhyDataMesh.md @@ -81,7 +81,7 @@ graph LR ## Data is Addressed, Not Copied -Data stays where it lives. Consumers reference it by address — `@FutuRe/EuropeRe/Analysis` — zero copies, zero staleness, zero reconciliation. +Data stays where it lives. Each BU's datacube is embedded in its own Analysis MeshNode — the same node that defines the hub, its layout areas, and its configuration. Consumers reference it by address — `@FutuRe/EuropeRe/Analysis` — zero copies, zero staleness, zero reconciliation. This works identically across all deployment modes (filesystem, PostgreSQL, Azure).
diff --git a/samples/Graph/Data/FutuRe/index.md b/samples/Graph/Data/FutuRe/index.md index eb59a53e4..f15cedf82 100644 --- a/samples/Graph/Data/FutuRe/index.md +++ b/samples/Graph/Data/FutuRe/index.md @@ -255,7 +255,9 @@ The group profitability dashboard assembles data from all business units in real # Data Where It Belongs -No ETL pipelines. No nightly batch jobs. No stale copies. Each BU owns its data. The group view is assembled virtually through reactive stream composition. When EuropeRe updates a number, the group dashboard updates instantly. +No ETL pipelines. No nightly batch jobs. No stale copies. Each BU owns its data — embedded directly in its Analysis MeshNode. The group view is assembled virtually through reactive stream composition. When EuropeRe updates a number, the group dashboard updates instantly. + +This architecture is deployment-mode independent: the same data flows work whether running as a standalone monolith on the filesystem, with PostgreSQL in local development, or distributed across Azure Container Apps. BU data ownership is preserved at every level. - [How virtual data distribution works →](@FutuRe/DataDistribution) diff --git a/samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv b/samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv deleted file mode 100644 index 6dd339e4e..000000000 --- a/samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv +++ /dev/null @@ -1,865 +0,0 @@ -Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual -2024-09,Q3-2024,2024,AGRICULTURE,CapitalCost,770000, -2024-09,Q3-2024,2024,AGRICULTURE,Claims,10885000,11102700 -2024-09,Q3-2024,2024,AGRICULTURE,ExpectedProfit,700000, -2024-09,Q3-2024,2024,AGRICULTURE,ExternalCost,1400000,1428000 -2024-09,Q3-2024,2024,AGRICULTURE,InternalCost,1680000, -2024-09,Q3-2024,2024,AGRICULTURE,Premium,14000000,14280000 -2024-09,Q3-2024,2024,COMMERCIAL,CapitalCost,2640000, -2024-09,Q3-2024,2024,COMMERCIAL,Claims,32342613,32989465 -2024-09,Q3-2024,2024,COMMERCIAL,ExpectedProfit,2400000, -2024-09,Q3-2024,2024,COMMERCIAL,ExternalCost,4800000,4896000 -2024-09,Q3-2024,2024,COMMERCIAL,InternalCost,5760000, -2024-09,Q3-2024,2024,COMMERCIAL,Premium,48000000,48960000 -2024-09,Q3-2024,2024,CYBER_TECH,CapitalCost,550000, -2024-09,Q3-2024,2024,CYBER_TECH,Claims,4656000,4749120 -2024-09,Q3-2024,2024,CYBER_TECH,ExpectedProfit,500000, -2024-09,Q3-2024,2024,CYBER_TECH,ExternalCost,1000000,1020000 -2024-09,Q3-2024,2024,CYBER_TECH,InternalCost,1200000, -2024-09,Q3-2024,2024,CYBER_TECH,Premium,10000000,10200000 -2024-09,Q3-2024,2024,ENERGY_MINING,CapitalCost,1815000, -2024-09,Q3-2024,2024,ENERGY_MINING,Claims,23031067,23491688 -2024-09,Q3-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, -2024-09,Q3-2024,2024,ENERGY_MINING,ExternalCost,3300000,3366000 -2024-09,Q3-2024,2024,ENERGY_MINING,InternalCost,3960000, -2024-09,Q3-2024,2024,ENERGY_MINING,Premium,33000000,33660000 -2024-09,Q3-2024,2024,HOMEOWNERS,CapitalCost,3410000, -2024-09,Q3-2024,2024,HOMEOWNERS,Claims,51605987,52638107 -2024-09,Q3-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, -2024-09,Q3-2024,2024,HOMEOWNERS,ExternalCost,6200000,6324000 -2024-09,Q3-2024,2024,HOMEOWNERS,InternalCost,7440000, -2024-09,Q3-2024,2024,HOMEOWNERS,Premium,65720000,67034400 -2024-09,Q3-2024,2024,LIFE_ANN,CapitalCost,2090000, -2024-09,Q3-2024,2024,LIFE_ANN,Claims,20900000,21318000 -2024-09,Q3-2024,2024,LIFE_ANN,ExpectedProfit,1900000, -2024-09,Q3-2024,2024,LIFE_ANN,ExternalCost,3800000,3876000 -2024-09,Q3-2024,2024,LIFE_ANN,InternalCost,4560000, -2024-09,Q3-2024,2024,LIFE_ANN,Premium,38000000,38760000 -2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, -2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,11566800 -2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1836000 -2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, -2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,18360000 -2024-09,Q3-2024,2024,WORKERS_COMP,CapitalCost,2310000, -2024-09,Q3-2024,2024,WORKERS_COMP,Claims,26493600,27023472 -2024-09,Q3-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, -2024-09,Q3-2024,2024,WORKERS_COMP,ExternalCost,4200000,4284000 -2024-09,Q3-2024,2024,WORKERS_COMP,InternalCost,5040000, -2024-09,Q3-2024,2024,WORKERS_COMP,Premium,42000000,42840000 -2024-10,Q4-2024,2024,AGRICULTURE,CapitalCost,770000, -2024-10,Q4-2024,2024,AGRICULTURE,Claims,9902200,9605134 -2024-10,Q4-2024,2024,AGRICULTURE,ExpectedProfit,700000, -2024-10,Q4-2024,2024,AGRICULTURE,ExternalCost,1400000,1358000 -2024-10,Q4-2024,2024,AGRICULTURE,InternalCost,1680000, -2024-10,Q4-2024,2024,AGRICULTURE,Premium,14000000,13580000 -2024-10,Q4-2024,2024,COMMERCIAL,CapitalCost,2640000, -2024-10,Q4-2024,2024,COMMERCIAL,Claims,31113813,30180399 -2024-10,Q4-2024,2024,COMMERCIAL,ExpectedProfit,2400000, -2024-10,Q4-2024,2024,COMMERCIAL,ExternalCost,4800000,4656000 -2024-10,Q4-2024,2024,COMMERCIAL,InternalCost,5760000, -2024-10,Q4-2024,2024,COMMERCIAL,Premium,48000000,46560000 -2024-10,Q4-2024,2024,CYBER_TECH,CapitalCost,550000, -2024-10,Q4-2024,2024,CYBER_TECH,Claims,5136000,4981920 -2024-10,Q4-2024,2024,CYBER_TECH,ExpectedProfit,500000, -2024-10,Q4-2024,2024,CYBER_TECH,ExternalCost,1000000,970000 -2024-10,Q4-2024,2024,CYBER_TECH,InternalCost,1200000, -2024-10,Q4-2024,2024,CYBER_TECH,Premium,10000000,9700000 -2024-10,Q4-2024,2024,ENERGY_MINING,CapitalCost,1815000, -2024-10,Q4-2024,2024,ENERGY_MINING,Claims,21183067,20547575 -2024-10,Q4-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, -2024-10,Q4-2024,2024,ENERGY_MINING,ExternalCost,3300000,3201000 -2024-10,Q4-2024,2024,ENERGY_MINING,InternalCost,3960000, -2024-10,Q4-2024,2024,ENERGY_MINING,Premium,33000000,32010000 -2024-10,Q4-2024,2024,HOMEOWNERS,CapitalCost,3410000, -2024-10,Q4-2024,2024,HOMEOWNERS,Claims,48360101,46909298 -2024-10,Q4-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, -2024-10,Q4-2024,2024,HOMEOWNERS,ExternalCost,6200000,6014000 -2024-10,Q4-2024,2024,HOMEOWNERS,InternalCost,7440000, -2024-10,Q4-2024,2024,HOMEOWNERS,Premium,63240000,61342800 -2024-10,Q4-2024,2024,LIFE_ANN,CapitalCost,2090000, -2024-10,Q4-2024,2024,LIFE_ANN,Claims,20900000,20273000 -2024-10,Q4-2024,2024,LIFE_ANN,ExpectedProfit,1900000, -2024-10,Q4-2024,2024,LIFE_ANN,ExternalCost,3800000,3686000 -2024-10,Q4-2024,2024,LIFE_ANN,InternalCost,4560000, -2024-10,Q4-2024,2024,LIFE_ANN,Premium,38000000,36860000 -2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, -2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,10999800 -2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1746000 -2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, -2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,17460000 -2024-10,Q4-2024,2024,WORKERS_COMP,CapitalCost,2310000, -2024-10,Q4-2024,2024,WORKERS_COMP,Claims,25384800,24623256 -2024-10,Q4-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, -2024-10,Q4-2024,2024,WORKERS_COMP,ExternalCost,4200000,4074000 -2024-10,Q4-2024,2024,WORKERS_COMP,InternalCost,5040000, -2024-10,Q4-2024,2024,WORKERS_COMP,Premium,42000000,40740000 -2024-11,Q4-2024,2024,AGRICULTURE,CapitalCost,770000, -2024-11,Q4-2024,2024,AGRICULTURE,Claims,8919400,9365370 -2024-11,Q4-2024,2024,AGRICULTURE,ExpectedProfit,700000, -2024-11,Q4-2024,2024,AGRICULTURE,ExternalCost,1400000,1470000 -2024-11,Q4-2024,2024,AGRICULTURE,InternalCost,1680000, -2024-11,Q4-2024,2024,AGRICULTURE,Premium,14000000,14700000 -2024-11,Q4-2024,2024,COMMERCIAL,CapitalCost,2640000, -2024-11,Q4-2024,2024,COMMERCIAL,Claims,29885013,31379264 -2024-11,Q4-2024,2024,COMMERCIAL,ExpectedProfit,2400000, -2024-11,Q4-2024,2024,COMMERCIAL,ExternalCost,4800000,5040000 -2024-11,Q4-2024,2024,COMMERCIAL,InternalCost,5760000, -2024-11,Q4-2024,2024,COMMERCIAL,Premium,48000000,50400000 -2024-11,Q4-2024,2024,CYBER_TECH,CapitalCost,550000, -2024-11,Q4-2024,2024,CYBER_TECH,Claims,5424000,5695200 -2024-11,Q4-2024,2024,CYBER_TECH,ExpectedProfit,500000, -2024-11,Q4-2024,2024,CYBER_TECH,ExternalCost,1000000,1050000 -2024-11,Q4-2024,2024,CYBER_TECH,InternalCost,1200000, -2024-11,Q4-2024,2024,CYBER_TECH,Premium,10000000,10500000 -2024-11,Q4-2024,2024,ENERGY_MINING,CapitalCost,1815000, -2024-11,Q4-2024,2024,ENERGY_MINING,Claims,20443867,21466060 -2024-11,Q4-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, -2024-11,Q4-2024,2024,ENERGY_MINING,ExternalCost,3300000,3465000 -2024-11,Q4-2024,2024,ENERGY_MINING,InternalCost,3960000, -2024-11,Q4-2024,2024,ENERGY_MINING,Premium,33000000,34650000 -2024-11,Q4-2024,2024,HOMEOWNERS,CapitalCost,3410000, -2024-11,Q4-2024,2024,HOMEOWNERS,Claims,41991600,44091180 -2024-11,Q4-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, -2024-11,Q4-2024,2024,HOMEOWNERS,ExternalCost,6200000,6510000 -2024-11,Q4-2024,2024,HOMEOWNERS,InternalCost,7440000, -2024-11,Q4-2024,2024,HOMEOWNERS,Premium,58900000,61845000 -2024-11,Q4-2024,2024,LIFE_ANN,CapitalCost,2090000, -2024-11,Q4-2024,2024,LIFE_ANN,Claims,20900000,21945000 -2024-11,Q4-2024,2024,LIFE_ANN,ExpectedProfit,1900000, -2024-11,Q4-2024,2024,LIFE_ANN,ExternalCost,3800000,3990000 -2024-11,Q4-2024,2024,LIFE_ANN,InternalCost,4560000, -2024-11,Q4-2024,2024,LIFE_ANN,Premium,38000000,39900000 -2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, -2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,11907000 -2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1890000 -2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, -2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,18900000 -2024-11,Q4-2024,2024,WORKERS_COMP,CapitalCost,2310000, -2024-11,Q4-2024,2024,WORKERS_COMP,Claims,23610720,24791256 -2024-11,Q4-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, -2024-11,Q4-2024,2024,WORKERS_COMP,ExternalCost,4200000,4410000 -2024-11,Q4-2024,2024,WORKERS_COMP,InternalCost,5040000, -2024-11,Q4-2024,2024,WORKERS_COMP,Premium,42000000,44100000 -2024-12,Q4-2024,2024,AGRICULTURE,CapitalCost,770000, -2024-12,Q4-2024,2024,AGRICULTURE,Claims,7936600,7777868 -2024-12,Q4-2024,2024,AGRICULTURE,ExpectedProfit,700000, -2024-12,Q4-2024,2024,AGRICULTURE,ExternalCost,1400000,1372000 -2024-12,Q4-2024,2024,AGRICULTURE,InternalCost,1680000, -2024-12,Q4-2024,2024,AGRICULTURE,Premium,14000000,13720000 -2024-12,Q4-2024,2024,COMMERCIAL,CapitalCost,2640000, -2024-12,Q4-2024,2024,COMMERCIAL,Claims,29393493,28805623 -2024-12,Q4-2024,2024,COMMERCIAL,ExpectedProfit,2400000, -2024-12,Q4-2024,2024,COMMERCIAL,ExternalCost,4800000,4704000 -2024-12,Q4-2024,2024,COMMERCIAL,InternalCost,5760000, -2024-12,Q4-2024,2024,COMMERCIAL,Premium,48000000,47040000 -2024-12,Q4-2024,2024,CYBER_TECH,CapitalCost,550000, -2024-12,Q4-2024,2024,CYBER_TECH,Claims,5904000,5785920 -2024-12,Q4-2024,2024,CYBER_TECH,ExpectedProfit,500000, -2024-12,Q4-2024,2024,CYBER_TECH,ExternalCost,1000000,980000 -2024-12,Q4-2024,2024,CYBER_TECH,InternalCost,1200000, -2024-12,Q4-2024,2024,CYBER_TECH,Premium,10000000,9800000 -2024-12,Q4-2024,2024,ENERGY_MINING,CapitalCost,1815000, -2024-12,Q4-2024,2024,ENERGY_MINING,Claims,21737467,21302718 -2024-12,Q4-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, -2024-12,Q4-2024,2024,ENERGY_MINING,ExternalCost,3300000,3234000 -2024-12,Q4-2024,2024,ENERGY_MINING,InternalCost,3960000, -2024-12,Q4-2024,2024,ENERGY_MINING,Premium,33000000,32340000 -2024-12,Q4-2024,2024,HOMEOWNERS,CapitalCost,3410000, -2024-12,Q4-2024,2024,HOMEOWNERS,Claims,40578139,39766576 -2024-12,Q4-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, -2024-12,Q4-2024,2024,HOMEOWNERS,ExternalCost,6200000,6076000 -2024-12,Q4-2024,2024,HOMEOWNERS,InternalCost,7440000, -2024-12,Q4-2024,2024,HOMEOWNERS,Premium,54560000,53468800 -2024-12,Q4-2024,2024,LIFE_ANN,CapitalCost,2090000, -2024-12,Q4-2024,2024,LIFE_ANN,Claims,20900000,20482000 -2024-12,Q4-2024,2024,LIFE_ANN,ExpectedProfit,1900000, -2024-12,Q4-2024,2024,LIFE_ANN,ExternalCost,3800000,3724000 -2024-12,Q4-2024,2024,LIFE_ANN,InternalCost,4560000, -2024-12,Q4-2024,2024,LIFE_ANN,Premium,38000000,37240000 -2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, -2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,11113200 -2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1764000 -2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, -2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,17640000 -2024-12,Q4-2024,2024,WORKERS_COMP,CapitalCost,2310000, -2024-12,Q4-2024,2024,WORKERS_COMP,Claims,22723680,22269206 -2024-12,Q4-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, -2024-12,Q4-2024,2024,WORKERS_COMP,ExternalCost,4200000,4116000 -2024-12,Q4-2024,2024,WORKERS_COMP,InternalCost,5040000, -2024-12,Q4-2024,2024,WORKERS_COMP,Premium,42000000,41160000 -2025-01,Q1-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-01,Q1-2025,2025,AGRICULTURE,Claims,7936600,8015966 -2025-01,Q1-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-01,Q1-2025,2025,AGRICULTURE,ExternalCost,1400000,1414000 -2025-01,Q1-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-01,Q1-2025,2025,AGRICULTURE,Premium,14000000,14140000 -2025-01,Q1-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-01,Q1-2025,2025,COMMERCIAL,Claims,31113813,31424951 -2025-01,Q1-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-01,Q1-2025,2025,COMMERCIAL,ExternalCost,4800000,4848000 -2025-01,Q1-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-01,Q1-2025,2025,COMMERCIAL,Premium,48000000,48480000 -2025-01,Q1-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-01,Q1-2025,2025,CYBER_TECH,Claims,5424000,5478240 -2025-01,Q1-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-01,Q1-2025,2025,CYBER_TECH,ExternalCost,1000000,1010000 -2025-01,Q1-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-01,Q1-2025,2025,CYBER_TECH,Premium,10000000,10100000 -2025-01,Q1-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-01,Q1-2025,2025,ENERGY_MINING,Claims,22291867,22514786 -2025-01,Q1-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-01,Q1-2025,2025,ENERGY_MINING,ExternalCost,3300000,3333000 -2025-01,Q1-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-01,Q1-2025,2025,ENERGY_MINING,Premium,33000000,33330000 -2025-01,Q1-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-01,Q1-2025,2025,HOMEOWNERS,Claims,41745056,42162507 -2025-01,Q1-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-01,Q1-2025,2025,HOMEOWNERS,ExternalCost,6200000,6262000 -2025-01,Q1-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-01,Q1-2025,2025,HOMEOWNERS,Premium,57660000,58236600 -2025-01,Q1-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-01,Q1-2025,2025,LIFE_ANN,Claims,20900000,21109000 -2025-01,Q1-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-01,Q1-2025,2025,LIFE_ANN,ExternalCost,3800000,3838000 -2025-01,Q1-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-01,Q1-2025,2025,LIFE_ANN,Premium,38000000,38380000 -2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11453400 -2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1818000 -2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18180000 -2025-01,Q1-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-01,Q1-2025,2025,WORKERS_COMP,Claims,24276000,24518760 -2025-01,Q1-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-01,Q1-2025,2025,WORKERS_COMP,ExternalCost,4200000,4242000 -2025-01,Q1-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-01,Q1-2025,2025,WORKERS_COMP,Premium,42000000,42420000 -2025-02,Q1-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-02,Q1-2025,2025,AGRICULTURE,Claims,8264200,7933632 -2025-02,Q1-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-02,Q1-2025,2025,AGRICULTURE,ExternalCost,1400000,1344000 -2025-02,Q1-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-02,Q1-2025,2025,AGRICULTURE,Premium,14000000,13440000 -2025-02,Q1-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-02,Q1-2025,2025,COMMERCIAL,Claims,29885013,28689612 -2025-02,Q1-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-02,Q1-2025,2025,COMMERCIAL,ExternalCost,4800000,4608000 -2025-02,Q1-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-02,Q1-2025,2025,COMMERCIAL,Premium,48000000,46080000 -2025-02,Q1-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-02,Q1-2025,2025,CYBER_TECH,Claims,4944000,4746240 -2025-02,Q1-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-02,Q1-2025,2025,CYBER_TECH,ExternalCost,1000000,960000 -2025-02,Q1-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-02,Q1-2025,2025,CYBER_TECH,Premium,10000000,9600000 -2025-02,Q1-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-02,Q1-2025,2025,ENERGY_MINING,Claims,21183067,20335744 -2025-02,Q1-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-02,Q1-2025,2025,ENERGY_MINING,ExternalCost,3300000,3168000 -2025-02,Q1-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-02,Q1-2025,2025,ENERGY_MINING,Premium,33000000,31680000 -2025-02,Q1-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-02,Q1-2025,2025,HOMEOWNERS,Claims,39998842,38398888 -2025-02,Q1-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-02,Q1-2025,2025,HOMEOWNERS,ExternalCost,6200000,5952000 -2025-02,Q1-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-02,Q1-2025,2025,HOMEOWNERS,Premium,55800000,53568000 -2025-02,Q1-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-02,Q1-2025,2025,LIFE_ANN,Claims,20900000,20064000 -2025-02,Q1-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-02,Q1-2025,2025,LIFE_ANN,ExternalCost,3800000,3648000 -2025-02,Q1-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-02,Q1-2025,2025,LIFE_ANN,Premium,38000000,36480000 -2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,10886400 -2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1728000 -2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17280000 -2025-02,Q1-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-02,Q1-2025,2025,WORKERS_COMP,Claims,23167200,22240512 -2025-02,Q1-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-02,Q1-2025,2025,WORKERS_COMP,ExternalCost,4200000,4032000 -2025-02,Q1-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-02,Q1-2025,2025,WORKERS_COMP,Premium,42000000,40320000 -2025-03,Q1-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-03,Q1-2025,2025,AGRICULTURE,Claims,8919400,9186982 -2025-03,Q1-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-03,Q1-2025,2025,AGRICULTURE,ExternalCost,1400000,1442000 -2025-03,Q1-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-03,Q1-2025,2025,AGRICULTURE,Premium,14000000,14420000 -2025-03,Q1-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-03,Q1-2025,2025,COMMERCIAL,Claims,28656213,29515899 -2025-03,Q1-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-03,Q1-2025,2025,COMMERCIAL,ExternalCost,4800000,4944000 -2025-03,Q1-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-03,Q1-2025,2025,COMMERCIAL,Premium,48000000,49440000 -2025-03,Q1-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-03,Q1-2025,2025,CYBER_TECH,Claims,4464000,4597920 -2025-03,Q1-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-03,Q1-2025,2025,CYBER_TECH,ExternalCost,1000000,1030000 -2025-03,Q1-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-03,Q1-2025,2025,CYBER_TECH,Premium,10000000,10300000 -2025-03,Q1-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-03,Q1-2025,2025,ENERGY_MINING,Claims,19335067,19915119 -2025-03,Q1-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-03,Q1-2025,2025,ENERGY_MINING,ExternalCost,3300000,3399000 -2025-03,Q1-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-03,Q1-2025,2025,ENERGY_MINING,Premium,33000000,33990000 -2025-03,Q1-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-03,Q1-2025,2025,HOMEOWNERS,Claims,36855814,37961488 -2025-03,Q1-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-03,Q1-2025,2025,HOMEOWNERS,ExternalCost,6200000,6386000 -2025-03,Q1-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-03,Q1-2025,2025,HOMEOWNERS,Premium,60760000,62582800 -2025-03,Q1-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-03,Q1-2025,2025,LIFE_ANN,Claims,20900000,21527000 -2025-03,Q1-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-03,Q1-2025,2025,LIFE_ANN,ExternalCost,3800000,3914000 -2025-03,Q1-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-03,Q1-2025,2025,LIFE_ANN,Premium,38000000,39140000 -2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11680200 -2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1854000 -2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18540000 -2025-03,Q1-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-03,Q1-2025,2025,WORKERS_COMP,Claims,25384800,26146344 -2025-03,Q1-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-03,Q1-2025,2025,WORKERS_COMP,ExternalCost,4200000,4326000 -2025-03,Q1-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-03,Q1-2025,2025,WORKERS_COMP,Premium,42000000,43260000 -2025-04,Q2-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-04,Q2-2025,2025,AGRICULTURE,Claims,9574600,9478854 -2025-04,Q2-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-04,Q2-2025,2025,AGRICULTURE,ExternalCost,1400000,1386000 -2025-04,Q2-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-04,Q2-2025,2025,AGRICULTURE,Premium,14000000,13860000 -2025-04,Q2-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-04,Q2-2025,2025,COMMERCIAL,Claims,27427413,27153139 -2025-04,Q2-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-04,Q2-2025,2025,COMMERCIAL,ExternalCost,4800000,4752000 -2025-04,Q2-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-04,Q2-2025,2025,COMMERCIAL,Premium,48000000,47520000 -2025-04,Q2-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-04,Q2-2025,2025,CYBER_TECH,Claims,4176000,4134240 -2025-04,Q2-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-04,Q2-2025,2025,CYBER_TECH,ExternalCost,1000000,990000 -2025-04,Q2-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-04,Q2-2025,2025,CYBER_TECH,Premium,10000000,9900000 -2025-04,Q2-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-04,Q2-2025,2025,ENERGY_MINING,Claims,18595867,18409908 -2025-04,Q2-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-04,Q2-2025,2025,ENERGY_MINING,ExternalCost,3300000,3267000 -2025-04,Q2-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-04,Q2-2025,2025,ENERGY_MINING,Premium,33000000,32670000 -2025-04,Q2-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-04,Q2-2025,2025,HOMEOWNERS,Claims,35725957,35368697 -2025-04,Q2-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-04,Q2-2025,2025,HOMEOWNERS,ExternalCost,6200000,6138000 -2025-04,Q2-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-04,Q2-2025,2025,HOMEOWNERS,Premium,62000000,61380000 -2025-04,Q2-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-04,Q2-2025,2025,LIFE_ANN,Claims,20900000,20691000 -2025-04,Q2-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-04,Q2-2025,2025,LIFE_ANN,ExternalCost,3800000,3762000 -2025-04,Q2-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-04,Q2-2025,2025,LIFE_ANN,Premium,38000000,37620000 -2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11226600 -2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1782000 -2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17820000 -2025-04,Q2-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-04,Q2-2025,2025,WORKERS_COMP,Claims,26493600,26228664 -2025-04,Q2-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-04,Q2-2025,2025,WORKERS_COMP,ExternalCost,4200000,4158000 -2025-04,Q2-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-04,Q2-2025,2025,WORKERS_COMP,Premium,42000000,41580000 -2025-05,Q2-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-05,Q2-2025,2025,AGRICULTURE,Claims,10557400,10979696 -2025-05,Q2-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-05,Q2-2025,2025,AGRICULTURE,ExternalCost,1400000,1456000 -2025-05,Q2-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-05,Q2-2025,2025,AGRICULTURE,Premium,14000000,14560000 -2025-05,Q2-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-05,Q2-2025,2025,COMMERCIAL,Claims,27918933,29035690 -2025-05,Q2-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-05,Q2-2025,2025,COMMERCIAL,ExternalCost,4800000,4992000 -2025-05,Q2-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-05,Q2-2025,2025,COMMERCIAL,Premium,48000000,49920000 -2025-05,Q2-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-05,Q2-2025,2025,CYBER_TECH,Claims,4320000,4492800 -2025-05,Q2-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-05,Q2-2025,2025,CYBER_TECH,ExternalCost,1000000,1040000 -2025-05,Q2-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-05,Q2-2025,2025,CYBER_TECH,Premium,10000000,10400000 -2025-05,Q2-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-05,Q2-2025,2025,ENERGY_MINING,Claims,18965467,19724086 -2025-05,Q2-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-05,Q2-2025,2025,ENERGY_MINING,ExternalCost,3300000,3432000 -2025-05,Q2-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-05,Q2-2025,2025,ENERGY_MINING,Premium,33000000,34320000 -2025-05,Q2-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-05,Q2-2025,2025,HOMEOWNERS,Claims,37044884,38526679 -2025-05,Q2-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-05,Q2-2025,2025,HOMEOWNERS,ExternalCost,6200000,6448000 -2025-05,Q2-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-05,Q2-2025,2025,HOMEOWNERS,Premium,64480000,67059200 -2025-05,Q2-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-05,Q2-2025,2025,LIFE_ANN,Claims,20900000,21736000 -2025-05,Q2-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-05,Q2-2025,2025,LIFE_ANN,ExternalCost,3800000,3952000 -2025-05,Q2-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-05,Q2-2025,2025,LIFE_ANN,Premium,38000000,39520000 -2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11793600 -2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1872000 -2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18720000 -2025-05,Q2-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-05,Q2-2025,2025,WORKERS_COMP,Claims,27158880,28245235 -2025-05,Q2-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-05,Q2-2025,2025,WORKERS_COMP,ExternalCost,4200000,4368000 -2025-05,Q2-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-05,Q2-2025,2025,WORKERS_COMP,Premium,42000000,43680000 -2025-06,Q2-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-06,Q2-2025,2025,AGRICULTURE,Claims,11212600,10651970 -2025-06,Q2-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-06,Q2-2025,2025,AGRICULTURE,ExternalCost,1400000,1330000 -2025-06,Q2-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-06,Q2-2025,2025,AGRICULTURE,Premium,14000000,13300000 -2025-06,Q2-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-06,Q2-2025,2025,COMMERCIAL,Claims,29885013,28390762 -2025-06,Q2-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-06,Q2-2025,2025,COMMERCIAL,ExternalCost,4800000,4560000 -2025-06,Q2-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-06,Q2-2025,2025,COMMERCIAL,Premium,48000000,45600000 -2025-06,Q2-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-06,Q2-2025,2025,CYBER_TECH,Claims,4656000,4423200 -2025-06,Q2-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-06,Q2-2025,2025,CYBER_TECH,ExternalCost,1000000,950000 -2025-06,Q2-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-06,Q2-2025,2025,CYBER_TECH,Premium,10000000,9500000 -2025-06,Q2-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-06,Q2-2025,2025,ENERGY_MINING,Claims,22291867,21177274 -2025-06,Q2-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-06,Q2-2025,2025,ENERGY_MINING,ExternalCost,3300000,3135000 -2025-06,Q2-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-06,Q2-2025,2025,ENERGY_MINING,Premium,33000000,31350000 -2025-06,Q2-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-06,Q2-2025,2025,HOMEOWNERS,Claims,39464930,37491684 -2025-06,Q2-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-06,Q2-2025,2025,HOMEOWNERS,ExternalCost,6200000,5890000 -2025-06,Q2-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-06,Q2-2025,2025,HOMEOWNERS,Premium,66960000,63612000 -2025-06,Q2-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-06,Q2-2025,2025,LIFE_ANN,Claims,20900000,19855000 -2025-06,Q2-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-06,Q2-2025,2025,LIFE_ANN,ExternalCost,3800000,3610000 -2025-06,Q2-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-06,Q2-2025,2025,LIFE_ANN,Premium,38000000,36100000 -2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,10773000 -2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1710000 -2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17100000 -2025-06,Q2-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-06,Q2-2025,2025,WORKERS_COMP,Claims,27602400,26222280 -2025-06,Q2-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-06,Q2-2025,2025,WORKERS_COMP,ExternalCost,4200000,3990000 -2025-06,Q2-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-06,Q2-2025,2025,WORKERS_COMP,Premium,42000000,39900000 -2025-07,Q3-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-07,Q3-2025,2025,AGRICULTURE,Claims,11867800,12579868 -2025-07,Q3-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-07,Q3-2025,2025,AGRICULTURE,ExternalCost,1400000,1484000 -2025-07,Q3-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-07,Q3-2025,2025,AGRICULTURE,Premium,14000000,14840000 -2025-07,Q3-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-07,Q3-2025,2025,COMMERCIAL,Claims,31113813,32980642 -2025-07,Q3-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-07,Q3-2025,2025,COMMERCIAL,ExternalCost,4800000,5088000 -2025-07,Q3-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-07,Q3-2025,2025,COMMERCIAL,Premium,48000000,50880000 -2025-07,Q3-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-07,Q3-2025,2025,CYBER_TECH,Claims,4944000,5240640 -2025-07,Q3-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-07,Q3-2025,2025,CYBER_TECH,ExternalCost,1000000,1060000 -2025-07,Q3-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-07,Q3-2025,2025,CYBER_TECH,Premium,10000000,10600000 -2025-07,Q3-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-07,Q3-2025,2025,ENERGY_MINING,Claims,23031067,24412931 -2025-07,Q3-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-07,Q3-2025,2025,ENERGY_MINING,ExternalCost,3300000,3498000 -2025-07,Q3-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-07,Q3-2025,2025,ENERGY_MINING,Premium,33000000,34980000 -2025-07,Q3-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-07,Q3-2025,2025,HOMEOWNERS,Claims,44087216,46732449 -2025-07,Q3-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-07,Q3-2025,2025,HOMEOWNERS,ExternalCost,6200000,6572000 -2025-07,Q3-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-07,Q3-2025,2025,HOMEOWNERS,Premium,69440000,73606400 -2025-07,Q3-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-07,Q3-2025,2025,LIFE_ANN,Claims,20900000,22154000 -2025-07,Q3-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-07,Q3-2025,2025,LIFE_ANN,ExternalCost,3800000,4028000 -2025-07,Q3-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-07,Q3-2025,2025,LIFE_ANN,Premium,38000000,40280000 -2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,12020400 -2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1908000 -2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,19080000 -2025-07,Q3-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-07,Q3-2025,2025,WORKERS_COMP,Claims,28045920,29728675 -2025-07,Q3-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-07,Q3-2025,2025,WORKERS_COMP,ExternalCost,4200000,4452000 -2025-07,Q3-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-07,Q3-2025,2025,WORKERS_COMP,Premium,42000000,44520000 -2025-08,Q3-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-08,Q3-2025,2025,AGRICULTURE,Claims,11540200,11309396 -2025-08,Q3-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-08,Q3-2025,2025,AGRICULTURE,ExternalCost,1400000,1372000 -2025-08,Q3-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-08,Q3-2025,2025,AGRICULTURE,Premium,14000000,13720000 -2025-08,Q3-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-08,Q3-2025,2025,COMMERCIAL,Claims,31851093,31214071 -2025-08,Q3-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-08,Q3-2025,2025,COMMERCIAL,ExternalCost,4800000,4704000 -2025-08,Q3-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-08,Q3-2025,2025,COMMERCIAL,Premium,48000000,47040000 -2025-08,Q3-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-08,Q3-2025,2025,CYBER_TECH,Claims,4464000,4374720 -2025-08,Q3-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-08,Q3-2025,2025,CYBER_TECH,ExternalCost,1000000,980000 -2025-08,Q3-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-08,Q3-2025,2025,CYBER_TECH,Premium,10000000,9800000 -2025-08,Q3-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-08,Q3-2025,2025,ENERGY_MINING,Claims,24139867,23657070 -2025-08,Q3-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-08,Q3-2025,2025,ENERGY_MINING,ExternalCost,3300000,3234000 -2025-08,Q3-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-08,Q3-2025,2025,ENERGY_MINING,Premium,33000000,32340000 -2025-08,Q3-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-08,Q3-2025,2025,HOMEOWNERS,Claims,49346273,48359348 -2025-08,Q3-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-08,Q3-2025,2025,HOMEOWNERS,ExternalCost,6200000,6076000 -2025-08,Q3-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-08,Q3-2025,2025,HOMEOWNERS,Premium,68200000,66836000 -2025-08,Q3-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-08,Q3-2025,2025,LIFE_ANN,Claims,20900000,20482000 -2025-08,Q3-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-08,Q3-2025,2025,LIFE_ANN,ExternalCost,3800000,3724000 -2025-08,Q3-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-08,Q3-2025,2025,LIFE_ANN,Premium,38000000,37240000 -2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11113200 -2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1764000 -2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17640000 -2025-08,Q3-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-08,Q3-2025,2025,WORKERS_COMP,Claims,27602400,27050352 -2025-08,Q3-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-08,Q3-2025,2025,WORKERS_COMP,ExternalCost,4200000,4116000 -2025-08,Q3-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-08,Q3-2025,2025,WORKERS_COMP,Premium,42000000,41160000 -2025-09,Q3-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-09,Q3-2025,2025,AGRICULTURE,Claims,10885000,10993850 -2025-09,Q3-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-09,Q3-2025,2025,AGRICULTURE,ExternalCost,1400000,1414000 -2025-09,Q3-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-09,Q3-2025,2025,AGRICULTURE,Premium,14000000,14140000 -2025-09,Q3-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-09,Q3-2025,2025,COMMERCIAL,Claims,32342613,32666039 -2025-09,Q3-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-09,Q3-2025,2025,COMMERCIAL,ExternalCost,4800000,4848000 -2025-09,Q3-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-09,Q3-2025,2025,COMMERCIAL,Premium,48000000,48480000 -2025-09,Q3-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-09,Q3-2025,2025,CYBER_TECH,Claims,4656000,4702560 -2025-09,Q3-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-09,Q3-2025,2025,CYBER_TECH,ExternalCost,1000000,1010000 -2025-09,Q3-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-09,Q3-2025,2025,CYBER_TECH,Premium,10000000,10100000 -2025-09,Q3-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-09,Q3-2025,2025,ENERGY_MINING,Claims,23031067,23261378 -2025-09,Q3-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-09,Q3-2025,2025,ENERGY_MINING,ExternalCost,3300000,3333000 -2025-09,Q3-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-09,Q3-2025,2025,ENERGY_MINING,Premium,33000000,33330000 -2025-09,Q3-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-09,Q3-2025,2025,HOMEOWNERS,Claims,51605987,52122047 -2025-09,Q3-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-09,Q3-2025,2025,HOMEOWNERS,ExternalCost,6200000,6262000 -2025-09,Q3-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-09,Q3-2025,2025,HOMEOWNERS,Premium,65720000,66377200 -2025-09,Q3-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-09,Q3-2025,2025,LIFE_ANN,Claims,20900000,21109000 -2025-09,Q3-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-09,Q3-2025,2025,LIFE_ANN,ExternalCost,3800000,3838000 -2025-09,Q3-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-09,Q3-2025,2025,LIFE_ANN,Premium,38000000,38380000 -2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11453400 -2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1818000 -2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18180000 -2025-09,Q3-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-09,Q3-2025,2025,WORKERS_COMP,Claims,26493600,26758536 -2025-09,Q3-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-09,Q3-2025,2025,WORKERS_COMP,ExternalCost,4200000,4242000 -2025-09,Q3-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-09,Q3-2025,2025,WORKERS_COMP,Premium,42000000,42420000 -2025-10,Q4-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-10,Q4-2025,2025,AGRICULTURE,Claims,9902200,9605134 -2025-10,Q4-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-10,Q4-2025,2025,AGRICULTURE,ExternalCost,1400000,1358000 -2025-10,Q4-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-10,Q4-2025,2025,AGRICULTURE,Premium,14000000,13580000 -2025-10,Q4-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-10,Q4-2025,2025,COMMERCIAL,Claims,31113813,30180399 -2025-10,Q4-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-10,Q4-2025,2025,COMMERCIAL,ExternalCost,4800000,4656000 -2025-10,Q4-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-10,Q4-2025,2025,COMMERCIAL,Premium,48000000,46560000 -2025-10,Q4-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-10,Q4-2025,2025,CYBER_TECH,Claims,5136000,4981920 -2025-10,Q4-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-10,Q4-2025,2025,CYBER_TECH,ExternalCost,1000000,970000 -2025-10,Q4-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-10,Q4-2025,2025,CYBER_TECH,Premium,10000000,9700000 -2025-10,Q4-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-10,Q4-2025,2025,ENERGY_MINING,Claims,21183067,20547575 -2025-10,Q4-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-10,Q4-2025,2025,ENERGY_MINING,ExternalCost,3300000,3201000 -2025-10,Q4-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-10,Q4-2025,2025,ENERGY_MINING,Premium,33000000,32010000 -2025-10,Q4-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-10,Q4-2025,2025,HOMEOWNERS,Claims,48360101,46909298 -2025-10,Q4-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-10,Q4-2025,2025,HOMEOWNERS,ExternalCost,6200000,6014000 -2025-10,Q4-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-10,Q4-2025,2025,HOMEOWNERS,Premium,63240000,61342800 -2025-10,Q4-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-10,Q4-2025,2025,LIFE_ANN,Claims,20900000,20273000 -2025-10,Q4-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-10,Q4-2025,2025,LIFE_ANN,ExternalCost,3800000,3686000 -2025-10,Q4-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-10,Q4-2025,2025,LIFE_ANN,Premium,38000000,36860000 -2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,10999800 -2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1746000 -2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17460000 -2025-10,Q4-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-10,Q4-2025,2025,WORKERS_COMP,Claims,25384800,24623256 -2025-10,Q4-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-10,Q4-2025,2025,WORKERS_COMP,ExternalCost,4200000,4074000 -2025-10,Q4-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-10,Q4-2025,2025,WORKERS_COMP,Premium,42000000,40740000 -2025-11,Q4-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-11,Q4-2025,2025,AGRICULTURE,Claims,8919400,9186982 -2025-11,Q4-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-11,Q4-2025,2025,AGRICULTURE,ExternalCost,1400000,1442000 -2025-11,Q4-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-11,Q4-2025,2025,AGRICULTURE,Premium,14000000,14420000 -2025-11,Q4-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-11,Q4-2025,2025,COMMERCIAL,Claims,29885013,30781563 -2025-11,Q4-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-11,Q4-2025,2025,COMMERCIAL,ExternalCost,4800000,4944000 -2025-11,Q4-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-11,Q4-2025,2025,COMMERCIAL,Premium,48000000,49440000 -2025-11,Q4-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-11,Q4-2025,2025,CYBER_TECH,Claims,5424000,5586720 -2025-11,Q4-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-11,Q4-2025,2025,CYBER_TECH,ExternalCost,1000000,1030000 -2025-11,Q4-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-11,Q4-2025,2025,CYBER_TECH,Premium,10000000,10300000 -2025-11,Q4-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-11,Q4-2025,2025,ENERGY_MINING,Claims,20443867,21057183 -2025-11,Q4-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-11,Q4-2025,2025,ENERGY_MINING,ExternalCost,3300000,3399000 -2025-11,Q4-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-11,Q4-2025,2025,ENERGY_MINING,Premium,33000000,33990000 -2025-11,Q4-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-11,Q4-2025,2025,HOMEOWNERS,Claims,41991600,43251348 -2025-11,Q4-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-11,Q4-2025,2025,HOMEOWNERS,ExternalCost,6200000,6386000 -2025-11,Q4-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-11,Q4-2025,2025,HOMEOWNERS,Premium,58900000,60667000 -2025-11,Q4-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-11,Q4-2025,2025,LIFE_ANN,Claims,20900000,21527000 -2025-11,Q4-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-11,Q4-2025,2025,LIFE_ANN,ExternalCost,3800000,3914000 -2025-11,Q4-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-11,Q4-2025,2025,LIFE_ANN,Premium,38000000,39140000 -2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11680200 -2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1854000 -2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18540000 -2025-11,Q4-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-11,Q4-2025,2025,WORKERS_COMP,Claims,23610720,24319042 -2025-11,Q4-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-11,Q4-2025,2025,WORKERS_COMP,ExternalCost,4200000,4326000 -2025-11,Q4-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-11,Q4-2025,2025,WORKERS_COMP,Premium,42000000,43260000 -2025-12,Q4-2025,2025,AGRICULTURE,CapitalCost,770000, -2025-12,Q4-2025,2025,AGRICULTURE,Claims,7936600,7936600 -2025-12,Q4-2025,2025,AGRICULTURE,ExpectedProfit,700000, -2025-12,Q4-2025,2025,AGRICULTURE,ExternalCost,1400000,1400000 -2025-12,Q4-2025,2025,AGRICULTURE,InternalCost,1680000, -2025-12,Q4-2025,2025,AGRICULTURE,Premium,14000000,14000000 -2025-12,Q4-2025,2025,COMMERCIAL,CapitalCost,2640000, -2025-12,Q4-2025,2025,COMMERCIAL,Claims,29393493,29393493 -2025-12,Q4-2025,2025,COMMERCIAL,ExpectedProfit,2400000, -2025-12,Q4-2025,2025,COMMERCIAL,ExternalCost,4800000,4800000 -2025-12,Q4-2025,2025,COMMERCIAL,InternalCost,5760000, -2025-12,Q4-2025,2025,COMMERCIAL,Premium,48000000,48000000 -2025-12,Q4-2025,2025,CYBER_TECH,CapitalCost,550000, -2025-12,Q4-2025,2025,CYBER_TECH,Claims,5904000,5904000 -2025-12,Q4-2025,2025,CYBER_TECH,ExpectedProfit,500000, -2025-12,Q4-2025,2025,CYBER_TECH,ExternalCost,1000000,1000000 -2025-12,Q4-2025,2025,CYBER_TECH,InternalCost,1200000, -2025-12,Q4-2025,2025,CYBER_TECH,Premium,10000000,10000000 -2025-12,Q4-2025,2025,ENERGY_MINING,CapitalCost,1815000, -2025-12,Q4-2025,2025,ENERGY_MINING,Claims,21737467,21737467 -2025-12,Q4-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, -2025-12,Q4-2025,2025,ENERGY_MINING,ExternalCost,3300000,3300000 -2025-12,Q4-2025,2025,ENERGY_MINING,InternalCost,3960000, -2025-12,Q4-2025,2025,ENERGY_MINING,Premium,33000000,33000000 -2025-12,Q4-2025,2025,HOMEOWNERS,CapitalCost,3410000, -2025-12,Q4-2025,2025,HOMEOWNERS,Claims,40578139,40578139 -2025-12,Q4-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, -2025-12,Q4-2025,2025,HOMEOWNERS,ExternalCost,6200000,6200000 -2025-12,Q4-2025,2025,HOMEOWNERS,InternalCost,7440000, -2025-12,Q4-2025,2025,HOMEOWNERS,Premium,54560000,54560000 -2025-12,Q4-2025,2025,LIFE_ANN,CapitalCost,2090000, -2025-12,Q4-2025,2025,LIFE_ANN,Claims,20900000,20900000 -2025-12,Q4-2025,2025,LIFE_ANN,ExpectedProfit,1900000, -2025-12,Q4-2025,2025,LIFE_ANN,ExternalCost,3800000,3800000 -2025-12,Q4-2025,2025,LIFE_ANN,InternalCost,4560000, -2025-12,Q4-2025,2025,LIFE_ANN,Premium,38000000,38000000 -2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, -2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11340000 -2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1800000 -2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, -2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18000000 -2025-12,Q4-2025,2025,WORKERS_COMP,CapitalCost,2310000, -2025-12,Q4-2025,2025,WORKERS_COMP,Claims,22723680,22723680 -2025-12,Q4-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, -2025-12,Q4-2025,2025,WORKERS_COMP,ExternalCost,4200000,4200000 -2025-12,Q4-2025,2025,WORKERS_COMP,InternalCost,5040000, -2025-12,Q4-2025,2025,WORKERS_COMP,Premium,42000000,42000000 -2026-01,Q1-2026,2026,AGRICULTURE,CapitalCost,770000, -2026-01,Q1-2026,2026,AGRICULTURE,Claims,7936600,7619136 -2026-01,Q1-2026,2026,AGRICULTURE,ExpectedProfit,700000, -2026-01,Q1-2026,2026,AGRICULTURE,ExternalCost,1400000,1344000 -2026-01,Q1-2026,2026,AGRICULTURE,InternalCost,1680000, -2026-01,Q1-2026,2026,AGRICULTURE,Premium,14000000,13440000 -2026-01,Q1-2026,2026,COMMERCIAL,CapitalCost,2640000, -2026-01,Q1-2026,2026,COMMERCIAL,Claims,31113813,29869260 -2026-01,Q1-2026,2026,COMMERCIAL,ExpectedProfit,2400000, -2026-01,Q1-2026,2026,COMMERCIAL,ExternalCost,4800000,4608000 -2026-01,Q1-2026,2026,COMMERCIAL,InternalCost,5760000, -2026-01,Q1-2026,2026,COMMERCIAL,Premium,48000000,46080000 -2026-01,Q1-2026,2026,CYBER_TECH,CapitalCost,550000, -2026-01,Q1-2026,2026,CYBER_TECH,Claims,5424000,5207040 -2026-01,Q1-2026,2026,CYBER_TECH,ExpectedProfit,500000, -2026-01,Q1-2026,2026,CYBER_TECH,ExternalCost,1000000,960000 -2026-01,Q1-2026,2026,CYBER_TECH,InternalCost,1200000, -2026-01,Q1-2026,2026,CYBER_TECH,Premium,10000000,9600000 -2026-01,Q1-2026,2026,ENERGY_MINING,CapitalCost,1815000, -2026-01,Q1-2026,2026,ENERGY_MINING,Claims,22291867,21400192 -2026-01,Q1-2026,2026,ENERGY_MINING,ExpectedProfit,1650000, -2026-01,Q1-2026,2026,ENERGY_MINING,ExternalCost,3300000,3168000 -2026-01,Q1-2026,2026,ENERGY_MINING,InternalCost,3960000, -2026-01,Q1-2026,2026,ENERGY_MINING,Premium,33000000,31680000 -2026-01,Q1-2026,2026,HOMEOWNERS,CapitalCost,3410000, -2026-01,Q1-2026,2026,HOMEOWNERS,Claims,41745056,40075254 -2026-01,Q1-2026,2026,HOMEOWNERS,ExpectedProfit,3100000, -2026-01,Q1-2026,2026,HOMEOWNERS,ExternalCost,6200000,5952000 -2026-01,Q1-2026,2026,HOMEOWNERS,InternalCost,7440000, -2026-01,Q1-2026,2026,HOMEOWNERS,Premium,57660000,55353600 -2026-01,Q1-2026,2026,LIFE_ANN,CapitalCost,2090000, -2026-01,Q1-2026,2026,LIFE_ANN,Claims,20900000,20064000 -2026-01,Q1-2026,2026,LIFE_ANN,ExpectedProfit,1900000, -2026-01,Q1-2026,2026,LIFE_ANN,ExternalCost,3800000,3648000 -2026-01,Q1-2026,2026,LIFE_ANN,InternalCost,4560000, -2026-01,Q1-2026,2026,LIFE_ANN,Premium,38000000,36480000 -2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,CapitalCost,990000, -2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,Claims,11340000,10886400 -2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,ExternalCost,1800000,1728000 -2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,InternalCost,2160000, -2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,Premium,18000000,17280000 -2026-01,Q1-2026,2026,WORKERS_COMP,CapitalCost,2310000, -2026-01,Q1-2026,2026,WORKERS_COMP,Claims,24276000,23304960 -2026-01,Q1-2026,2026,WORKERS_COMP,ExpectedProfit,2100000, -2026-01,Q1-2026,2026,WORKERS_COMP,ExternalCost,4200000,4032000 -2026-01,Q1-2026,2026,WORKERS_COMP,InternalCost,5040000, -2026-01,Q1-2026,2026,WORKERS_COMP,Premium,42000000,40320000 -2026-02,Q1-2026,2026,AGRICULTURE,CapitalCost,770000, -2026-02,Q1-2026,2026,AGRICULTURE,Claims,8264200,8429484 -2026-02,Q1-2026,2026,AGRICULTURE,ExpectedProfit,700000, -2026-02,Q1-2026,2026,AGRICULTURE,ExternalCost,1400000,1428000 -2026-02,Q1-2026,2026,AGRICULTURE,InternalCost,1680000, -2026-02,Q1-2026,2026,AGRICULTURE,Premium,14000000,14280000 -2026-02,Q1-2026,2026,COMMERCIAL,CapitalCost,2640000, -2026-02,Q1-2026,2026,COMMERCIAL,Claims,29885013,30482713 -2026-02,Q1-2026,2026,COMMERCIAL,ExpectedProfit,2400000, -2026-02,Q1-2026,2026,COMMERCIAL,ExternalCost,4800000,4896000 -2026-02,Q1-2026,2026,COMMERCIAL,InternalCost,5760000, -2026-02,Q1-2026,2026,COMMERCIAL,Premium,48000000,48960000 -2026-02,Q1-2026,2026,CYBER_TECH,CapitalCost,550000, -2026-02,Q1-2026,2026,CYBER_TECH,Claims,4944000,5042880 -2026-02,Q1-2026,2026,CYBER_TECH,ExpectedProfit,500000, -2026-02,Q1-2026,2026,CYBER_TECH,ExternalCost,1000000,1020000 -2026-02,Q1-2026,2026,CYBER_TECH,InternalCost,1200000, -2026-02,Q1-2026,2026,CYBER_TECH,Premium,10000000,10200000 -2026-02,Q1-2026,2026,ENERGY_MINING,CapitalCost,1815000, -2026-02,Q1-2026,2026,ENERGY_MINING,Claims,21183067,21606728 -2026-02,Q1-2026,2026,ENERGY_MINING,ExpectedProfit,1650000, -2026-02,Q1-2026,2026,ENERGY_MINING,ExternalCost,3300000,3366000 -2026-02,Q1-2026,2026,ENERGY_MINING,InternalCost,3960000, -2026-02,Q1-2026,2026,ENERGY_MINING,Premium,33000000,33660000 -2026-02,Q1-2026,2026,HOMEOWNERS,CapitalCost,3410000, -2026-02,Q1-2026,2026,HOMEOWNERS,Claims,39998842,40798819 -2026-02,Q1-2026,2026,HOMEOWNERS,ExpectedProfit,3100000, -2026-02,Q1-2026,2026,HOMEOWNERS,ExternalCost,6200000,6324000 -2026-02,Q1-2026,2026,HOMEOWNERS,InternalCost,7440000, -2026-02,Q1-2026,2026,HOMEOWNERS,Premium,55800000,56916000 -2026-02,Q1-2026,2026,LIFE_ANN,CapitalCost,2090000, -2026-02,Q1-2026,2026,LIFE_ANN,Claims,20900000,21318000 -2026-02,Q1-2026,2026,LIFE_ANN,ExpectedProfit,1900000, -2026-02,Q1-2026,2026,LIFE_ANN,ExternalCost,3800000,3876000 -2026-02,Q1-2026,2026,LIFE_ANN,InternalCost,4560000, -2026-02,Q1-2026,2026,LIFE_ANN,Premium,38000000,38760000 -2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,CapitalCost,990000, -2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,Claims,11340000,11566800 -2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,ExpectedProfit,900000, -2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,ExternalCost,1800000,1836000 -2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,InternalCost,2160000, -2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,Premium,18000000,18360000 -2026-02,Q1-2026,2026,WORKERS_COMP,CapitalCost,2310000, -2026-02,Q1-2026,2026,WORKERS_COMP,Claims,23167200,23630544 -2026-02,Q1-2026,2026,WORKERS_COMP,ExpectedProfit,2100000, -2026-02,Q1-2026,2026,WORKERS_COMP,ExternalCost,4200000,4284000 -2026-02,Q1-2026,2026,WORKERS_COMP,InternalCost,5040000, -2026-02,Q1-2026,2026,WORKERS_COMP,Premium,42000000,42840000 diff --git a/samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv b/samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv deleted file mode 100644 index 8ad3259b3..000000000 --- a/samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv +++ /dev/null @@ -1,865 +0,0 @@ -Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual -2024-09,Q3-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, -2024-09,Q3-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2449442168 -2024-09,Q3-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2024-09,Q3-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,414330739 -2024-09,Q3-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, -2024-09,Q3-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4223423702 -2024-09,Q3-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, -2024-09,Q3-2024,2024,CYBER_DIGITAL,Claims,720000000,740820742 -2024-09,Q3-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, -2024-09,Q3-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,151590295 -2024-09,Q3-2024,2024,CYBER_DIGITAL,InternalCost,180000000, -2024-09,Q3-2024,2024,CYBER_DIGITAL,Premium,1500000000,1483392644 -2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5486579879 -2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,776345941 -2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7922360025 -2024-09,Q3-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, -2024-09,Q3-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1244238708 -2024-09,Q3-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2024-09,Q3-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,180057837 -2024-09,Q3-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, -2024-09,Q3-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1766145400 -2024-09,Q3-2024,2024,MOTOR_TPL,CapitalCost,247500000, -2024-09,Q3-2024,2024,MOTOR_TPL,Claims,3330000000,3283070350 -2024-09,Q3-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, -2024-09,Q3-2024,2024,MOTOR_TPL,ExternalCost,450000000,454046880 -2024-09,Q3-2024,2024,MOTOR_TPL,InternalCost,540000000, -2024-09,Q3-2024,2024,MOTOR_TPL,Premium,4500000000,4414776475 -2024-09,Q3-2024,2024,PADDY_CROP,CapitalCost,132000000, -2024-09,Q3-2024,2024,PADDY_CROP,Claims,1872000000,1925888737 -2024-09,Q3-2024,2024,PADDY_CROP,ExpectedProfit,120000000, -2024-09,Q3-2024,2024,PADDY_CROP,ExternalCost,240000000,241285426 -2024-09,Q3-2024,2024,PADDY_CROP,InternalCost,288000000, -2024-09,Q3-2024,2024,PADDY_CROP,Premium,2400000000,2404314382 -2024-09,Q3-2024,2024,TRADE_CREDIT,CapitalCost,115500000, -2024-09,Q3-2024,2024,TRADE_CREDIT,Claims,1155000000,1120950485 -2024-09,Q3-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, -2024-09,Q3-2024,2024,TRADE_CREDIT,ExternalCost,210000000,213853323 -2024-09,Q3-2024,2024,TRADE_CREDIT,InternalCost,252000000, -2024-09,Q3-2024,2024,TRADE_CREDIT,Premium,2100000000,2125992158 -2024-09,Q3-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, -2024-09,Q3-2024,2024,TYPHOON_FLOOD,Claims,5814000000,6377621052 -2024-09,Q3-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, -2024-09,Q3-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,558217399 -2024-09,Q3-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, -2024-09,Q3-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5745175782 -2024-10,Q4-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, -2024-10,Q4-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2512257460 -2024-10,Q4-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2024-10,Q4-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,409737195 -2024-10,Q4-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, -2024-10,Q4-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4276811796 -2024-10,Q4-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, -2024-10,Q4-2024,2024,CYBER_DIGITAL,Claims,720000000,747215676 -2024-10,Q4-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, -2024-10,Q4-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,150933534 -2024-10,Q4-2024,2024,CYBER_DIGITAL,InternalCost,180000000, -2024-10,Q4-2024,2024,CYBER_DIGITAL,Premium,1500000000,1475802983 -2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5775373897 -2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,781695475 -2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7895824021 -2024-10,Q4-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, -2024-10,Q4-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1260356265 -2024-10,Q4-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2024-10,Q4-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,180562039 -2024-10,Q4-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, -2024-10,Q4-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1834064335 -2024-10,Q4-2024,2024,MOTOR_TPL,CapitalCost,247500000, -2024-10,Q4-2024,2024,MOTOR_TPL,Claims,3330000000,3394873662 -2024-10,Q4-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, -2024-10,Q4-2024,2024,MOTOR_TPL,ExternalCost,450000000,459766086 -2024-10,Q4-2024,2024,MOTOR_TPL,InternalCost,540000000, -2024-10,Q4-2024,2024,MOTOR_TPL,Premium,4500000000,4559292840 -2024-10,Q4-2024,2024,PADDY_CROP,CapitalCost,132000000, -2024-10,Q4-2024,2024,PADDY_CROP,Claims,1560000000,1601130565 -2024-10,Q4-2024,2024,PADDY_CROP,ExpectedProfit,120000000, -2024-10,Q4-2024,2024,PADDY_CROP,ExternalCost,240000000,233459871 -2024-10,Q4-2024,2024,PADDY_CROP,InternalCost,288000000, -2024-10,Q4-2024,2024,PADDY_CROP,Premium,2400000000,2407425806 -2024-10,Q4-2024,2024,TRADE_CREDIT,CapitalCost,115500000, -2024-10,Q4-2024,2024,TRADE_CREDIT,Claims,1155000000,1147089448 -2024-10,Q4-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, -2024-10,Q4-2024,2024,TRADE_CREDIT,ExternalCost,210000000,204705379 -2024-10,Q4-2024,2024,TRADE_CREDIT,InternalCost,252000000, -2024-10,Q4-2024,2024,TRADE_CREDIT,Premium,2100000000,2077143455 -2024-10,Q4-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, -2024-10,Q4-2024,2024,TYPHOON_FLOOD,Claims,3876000000,3791038523 -2024-10,Q4-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, -2024-10,Q4-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,562406697 -2024-10,Q4-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, -2024-10,Q4-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5639076322 -2024-11,Q4-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, -2024-11,Q4-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2517950167 -2024-11,Q4-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2024-11,Q4-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,416728560 -2024-11,Q4-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, -2024-11,Q4-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4222794987 -2024-11,Q4-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, -2024-11,Q4-2024,2024,CYBER_DIGITAL,Claims,720000000,713777923 -2024-11,Q4-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, -2024-11,Q4-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,153929891 -2024-11,Q4-2024,2024,CYBER_DIGITAL,InternalCost,180000000, -2024-11,Q4-2024,2024,CYBER_DIGITAL,Premium,1500000000,1482570422 -2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5721190378 -2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,764609289 -2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7846187040 -2024-11,Q4-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, -2024-11,Q4-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1238670971 -2024-11,Q4-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2024-11,Q4-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,178698119 -2024-11,Q4-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, -2024-11,Q4-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1816497129 -2024-11,Q4-2024,2024,MOTOR_TPL,CapitalCost,247500000, -2024-11,Q4-2024,2024,MOTOR_TPL,Claims,3330000000,3400595936 -2024-11,Q4-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, -2024-11,Q4-2024,2024,MOTOR_TPL,ExternalCost,450000000,451537643 -2024-11,Q4-2024,2024,MOTOR_TPL,InternalCost,540000000, -2024-11,Q4-2024,2024,MOTOR_TPL,Premium,4500000000,4588114203 -2024-11,Q4-2024,2024,PADDY_CROP,CapitalCost,132000000, -2024-11,Q4-2024,2024,PADDY_CROP,Claims,1560000000,1618387920 -2024-11,Q4-2024,2024,PADDY_CROP,ExpectedProfit,120000000, -2024-11,Q4-2024,2024,PADDY_CROP,ExternalCost,240000000,243974399 -2024-11,Q4-2024,2024,PADDY_CROP,InternalCost,288000000, -2024-11,Q4-2024,2024,PADDY_CROP,Premium,2400000000,2417722968 -2024-11,Q4-2024,2024,TRADE_CREDIT,CapitalCost,115500000, -2024-11,Q4-2024,2024,TRADE_CREDIT,Claims,1155000000,1123316063 -2024-11,Q4-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, -2024-11,Q4-2024,2024,TRADE_CREDIT,ExternalCost,210000000,207674708 -2024-11,Q4-2024,2024,TRADE_CREDIT,InternalCost,252000000, -2024-11,Q4-2024,2024,TRADE_CREDIT,Premium,2100000000,2077240038 -2024-11,Q4-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, -2024-11,Q4-2024,2024,TYPHOON_FLOOD,Claims,3876000000,3825141560 -2024-11,Q4-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, -2024-11,Q4-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,585147512 -2024-11,Q4-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, -2024-11,Q4-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5647044920 -2024-12,Q4-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, -2024-12,Q4-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2507839061 -2024-12,Q4-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2024-12,Q4-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,423917054 -2024-12,Q4-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, -2024-12,Q4-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4263229761 -2024-12,Q4-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, -2024-12,Q4-2024,2024,CYBER_DIGITAL,Claims,720000000,751077941 -2024-12,Q4-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, -2024-12,Q4-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,149629667 -2024-12,Q4-2024,2024,CYBER_DIGITAL,InternalCost,180000000, -2024-12,Q4-2024,2024,CYBER_DIGITAL,Premium,1500000000,1493737914 -2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5558324807 -2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,782872029 -2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7726642612 -2024-12,Q4-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, -2024-12,Q4-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1281126268 -2024-12,Q4-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2024-12,Q4-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,184296487 -2024-12,Q4-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, -2024-12,Q4-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1782917396 -2024-12,Q4-2024,2024,MOTOR_TPL,CapitalCost,247500000, -2024-12,Q4-2024,2024,MOTOR_TPL,Claims,3330000000,3288527050 -2024-12,Q4-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, -2024-12,Q4-2024,2024,MOTOR_TPL,ExternalCost,450000000,463433515 -2024-12,Q4-2024,2024,MOTOR_TPL,InternalCost,540000000, -2024-12,Q4-2024,2024,MOTOR_TPL,Premium,4500000000,4481892091 -2024-12,Q4-2024,2024,PADDY_CROP,CapitalCost,132000000, -2024-12,Q4-2024,2024,PADDY_CROP,Claims,1560000000,1524545495 -2024-12,Q4-2024,2024,PADDY_CROP,ExpectedProfit,120000000, -2024-12,Q4-2024,2024,PADDY_CROP,ExternalCost,240000000,233478476 -2024-12,Q4-2024,2024,PADDY_CROP,InternalCost,288000000, -2024-12,Q4-2024,2024,PADDY_CROP,Premium,2400000000,2400914524 -2024-12,Q4-2024,2024,TRADE_CREDIT,CapitalCost,115500000, -2024-12,Q4-2024,2024,TRADE_CREDIT,Claims,1155000000,1178326014 -2024-12,Q4-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, -2024-12,Q4-2024,2024,TRADE_CREDIT,ExternalCost,210000000,213680200 -2024-12,Q4-2024,2024,TRADE_CREDIT,InternalCost,252000000, -2024-12,Q4-2024,2024,TRADE_CREDIT,Premium,2100000000,2067210527 -2024-12,Q4-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, -2024-12,Q4-2024,2024,TYPHOON_FLOOD,Claims,3876000000,3779418671 -2024-12,Q4-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, -2024-12,Q4-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,565951380 -2024-12,Q4-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, -2024-12,Q4-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5682252472 -2025-01,Q1-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-01,Q1-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2551069452 -2025-01,Q1-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-01,Q1-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,431871175 -2025-01,Q1-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-01,Q1-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4283348392 -2025-01,Q1-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-01,Q1-2025,2025,CYBER_DIGITAL,Claims,720000000,699061307 -2025-01,Q1-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-01,Q1-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,151986496 -2025-01,Q1-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-01,Q1-2025,2025,CYBER_DIGITAL,Premium,1500000000,1521646782 -2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Claims,14040000000,15928556084 -2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,769087419 -2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7856693635 -2025-01,Q1-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-01,Q1-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1233444459 -2025-01,Q1-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-01,Q1-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,179295465 -2025-01,Q1-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-01,Q1-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1810149249 -2025-01,Q1-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-01,Q1-2025,2025,MOTOR_TPL,Claims,3330000000,3484196563 -2025-01,Q1-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-01,Q1-2025,2025,MOTOR_TPL,ExternalCost,450000000,460148029 -2025-01,Q1-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-01,Q1-2025,2025,MOTOR_TPL,Premium,4500000000,4491670267 -2025-01,Q1-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-01,Q1-2025,2025,PADDY_CROP,Claims,1560000000,1575673147 -2025-01,Q1-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-01,Q1-2025,2025,PADDY_CROP,ExternalCost,240000000,235372587 -2025-01,Q1-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-01,Q1-2025,2025,PADDY_CROP,Premium,2400000000,2377285349 -2025-01,Q1-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-01,Q1-2025,2025,TRADE_CREDIT,Claims,1155000000,1200785916 -2025-01,Q1-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-01,Q1-2025,2025,TRADE_CREDIT,ExternalCost,210000000,207460404 -2025-01,Q1-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-01,Q1-2025,2025,TRADE_CREDIT,Premium,2100000000,2134660739 -2025-01,Q1-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-01,Q1-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3948549483 -2025-01,Q1-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-01,Q1-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,558127103 -2025-01,Q1-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-01,Q1-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5731680485 -2025-02,Q1-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-02,Q1-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2553138812 -2025-02,Q1-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-02,Q1-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,427021387 -2025-02,Q1-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-02,Q1-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4244101814 -2025-02,Q1-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-02,Q1-2025,2025,CYBER_DIGITAL,Claims,720000000,698432941 -2025-02,Q1-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-02,Q1-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,148417405 -2025-02,Q1-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-02,Q1-2025,2025,CYBER_DIGITAL,Premium,1500000000,1501821220 -2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5864945426 -2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,797724184 -2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7650076744 -2025-02,Q1-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-02,Q1-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1253197424 -2025-02,Q1-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-02,Q1-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,175225592 -2025-02,Q1-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-02,Q1-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1823879918 -2025-02,Q1-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-02,Q1-2025,2025,MOTOR_TPL,Claims,3330000000,3482367332 -2025-02,Q1-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-02,Q1-2025,2025,MOTOR_TPL,ExternalCost,450000000,438812643 -2025-02,Q1-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-02,Q1-2025,2025,MOTOR_TPL,Premium,4500000000,4568041728 -2025-02,Q1-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-02,Q1-2025,2025,PADDY_CROP,Claims,1560000000,1521837722 -2025-02,Q1-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-02,Q1-2025,2025,PADDY_CROP,ExternalCost,240000000,243752671 -2025-02,Q1-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-02,Q1-2025,2025,PADDY_CROP,Premium,2400000000,2398655084 -2025-02,Q1-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-02,Q1-2025,2025,TRADE_CREDIT,Claims,1155000000,1132213371 -2025-02,Q1-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-02,Q1-2025,2025,TRADE_CREDIT,ExternalCost,210000000,209688558 -2025-02,Q1-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-02,Q1-2025,2025,TRADE_CREDIT,Premium,2100000000,2122330092 -2025-02,Q1-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-02,Q1-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3841908760 -2025-02,Q1-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-02,Q1-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,582737210 -2025-02,Q1-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-02,Q1-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5711355219 -2025-03,Q1-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-03,Q1-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2487098518 -2025-03,Q1-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-03,Q1-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,420990261 -2025-03,Q1-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-03,Q1-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4187087174 -2025-03,Q1-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-03,Q1-2025,2025,CYBER_DIGITAL,Claims,720000000,709986301 -2025-03,Q1-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-03,Q1-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,148305447 -2025-03,Q1-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-03,Q1-2025,2025,CYBER_DIGITAL,Premium,1500000000,1513795864 -2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5739497214 -2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,777103084 -2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7954486599 -2025-03,Q1-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-03,Q1-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1234397223 -2025-03,Q1-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-03,Q1-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,177026731 -2025-03,Q1-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-03,Q1-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1801265461 -2025-03,Q1-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-03,Q1-2025,2025,MOTOR_TPL,Claims,3330000000,3386825443 -2025-03,Q1-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-03,Q1-2025,2025,MOTOR_TPL,ExternalCost,450000000,442713098 -2025-03,Q1-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-03,Q1-2025,2025,MOTOR_TPL,Premium,4500000000,4470855401 -2025-03,Q1-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-03,Q1-2025,2025,PADDY_CROP,Claims,1560000000,1522059937 -2025-03,Q1-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-03,Q1-2025,2025,PADDY_CROP,ExternalCost,240000000,241887883 -2025-03,Q1-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-03,Q1-2025,2025,PADDY_CROP,Premium,2400000000,2373140869 -2025-03,Q1-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-03,Q1-2025,2025,TRADE_CREDIT,Claims,1155000000,1204010809 -2025-03,Q1-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-03,Q1-2025,2025,TRADE_CREDIT,ExternalCost,210000000,214531406 -2025-03,Q1-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-03,Q1-2025,2025,TRADE_CREDIT,Premium,2100000000,2077231110 -2025-03,Q1-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-03,Q1-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3833520477 -2025-03,Q1-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-03,Q1-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,575779040 -2025-03,Q1-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-03,Q1-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5602155476 -2025-04,Q2-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-04,Q2-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2471074069 -2025-04,Q2-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-04,Q2-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,430974959 -2025-04,Q2-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-04,Q2-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4151991784 -2025-04,Q2-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-04,Q2-2025,2025,CYBER_DIGITAL,Claims,720000000,725625851 -2025-04,Q2-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-04,Q2-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,152561575 -2025-04,Q2-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-04,Q2-2025,2025,CYBER_DIGITAL,Premium,1500000000,1504262586 -2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5533067366 -2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,761136362 -2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7895939063 -2025-04,Q2-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-04,Q2-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1264896725 -2025-04,Q2-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-04,Q2-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,179643866 -2025-04,Q2-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-04,Q2-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1795035685 -2025-04,Q2-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-04,Q2-2025,2025,MOTOR_TPL,Claims,3330000000,3409484315 -2025-04,Q2-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-04,Q2-2025,2025,MOTOR_TPL,ExternalCost,450000000,463072461 -2025-04,Q2-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-04,Q2-2025,2025,MOTOR_TPL,Premium,4500000000,4541233653 -2025-04,Q2-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-04,Q2-2025,2025,PADDY_CROP,Claims,1560000000,1563447136 -2025-04,Q2-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-04,Q2-2025,2025,PADDY_CROP,ExternalCost,240000000,237685958 -2025-04,Q2-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-04,Q2-2025,2025,PADDY_CROP,Premium,2400000000,2361448116 -2025-04,Q2-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-04,Q2-2025,2025,TRADE_CREDIT,Claims,1155000000,1143325845 -2025-04,Q2-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-04,Q2-2025,2025,TRADE_CREDIT,ExternalCost,210000000,206096632 -2025-04,Q2-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-04,Q2-2025,2025,TRADE_CREDIT,Premium,2100000000,2130380493 -2025-04,Q2-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-04,Q2-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3890537059 -2025-04,Q2-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-04,Q2-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,562426244 -2025-04,Q2-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-04,Q2-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5688283889 -2025-05,Q2-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-05,Q2-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2630530345 -2025-05,Q2-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-05,Q2-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,418566895 -2025-05,Q2-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-05,Q2-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4157967483 -2025-05,Q2-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-05,Q2-2025,2025,CYBER_DIGITAL,Claims,720000000,730098738 -2025-05,Q2-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-05,Q2-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,145955295 -2025-05,Q2-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-05,Q2-2025,2025,CYBER_DIGITAL,Premium,1500000000,1521680946 -2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5823130473 -2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,801949025 -2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7955776130 -2025-05,Q2-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-05,Q2-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1307748530 -2025-05,Q2-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-05,Q2-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,176396160 -2025-05,Q2-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-05,Q2-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1830698423 -2025-05,Q2-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-05,Q2-2025,2025,MOTOR_TPL,Claims,3330000000,3287042281 -2025-05,Q2-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-05,Q2-2025,2025,MOTOR_TPL,ExternalCost,450000000,447328088 -2025-05,Q2-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-05,Q2-2025,2025,MOTOR_TPL,Premium,4500000000,4497415403 -2025-05,Q2-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-05,Q2-2025,2025,PADDY_CROP,Claims,1560000000,1560495845 -2025-05,Q2-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-05,Q2-2025,2025,PADDY_CROP,ExternalCost,240000000,246988447 -2025-05,Q2-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-05,Q2-2025,2025,PADDY_CROP,Premium,2400000000,2357628998 -2025-05,Q2-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-05,Q2-2025,2025,TRADE_CREDIT,Claims,1155000000,1192798124 -2025-05,Q2-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-05,Q2-2025,2025,TRADE_CREDIT,ExternalCost,210000000,209433105 -2025-05,Q2-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-05,Q2-2025,2025,TRADE_CREDIT,Premium,2100000000,2080277057 -2025-05,Q2-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-05,Q2-2025,2025,TYPHOON_FLOOD,Claims,3876000000,4056565054 -2025-05,Q2-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-05,Q2-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,586943456 -2025-05,Q2-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-05,Q2-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5682445707 -2025-06,Q2-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-06,Q2-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2589231108 -2025-06,Q2-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-06,Q2-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,411300880 -2025-06,Q2-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-06,Q2-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4209369078 -2025-06,Q2-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-06,Q2-2025,2025,CYBER_DIGITAL,Claims,720000000,754197659 -2025-06,Q2-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-06,Q2-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,150712623 -2025-06,Q2-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-06,Q2-2025,2025,CYBER_DIGITAL,Premium,1500000000,1487802470 -2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5783570460 -2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,759275335 -2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7813164903 -2025-06,Q2-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-06,Q2-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1272887319 -2025-06,Q2-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-06,Q2-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,183809375 -2025-06,Q2-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-06,Q2-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1806060787 -2025-06,Q2-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-06,Q2-2025,2025,MOTOR_TPL,Claims,3330000000,3486051500 -2025-06,Q2-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-06,Q2-2025,2025,MOTOR_TPL,ExternalCost,450000000,438663010 -2025-06,Q2-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-06,Q2-2025,2025,MOTOR_TPL,Premium,4500000000,4438337891 -2025-06,Q2-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-06,Q2-2025,2025,PADDY_CROP,Claims,1560000000,1587460381 -2025-06,Q2-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-06,Q2-2025,2025,PADDY_CROP,ExternalCost,240000000,242523061 -2025-06,Q2-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-06,Q2-2025,2025,PADDY_CROP,Premium,2400000000,2369839196 -2025-06,Q2-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-06,Q2-2025,2025,TRADE_CREDIT,Claims,1155000000,1131427523 -2025-06,Q2-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-06,Q2-2025,2025,TRADE_CREDIT,ExternalCost,210000000,214917620 -2025-06,Q2-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-06,Q2-2025,2025,TRADE_CREDIT,Premium,2100000000,2077757127 -2025-06,Q2-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-06,Q2-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3944068499 -2025-06,Q2-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-06,Q2-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,574082848 -2025-06,Q2-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-06,Q2-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5642137099 -2025-07,Q3-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-07,Q3-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2562068334 -2025-07,Q3-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-07,Q3-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,420574124 -2025-07,Q3-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-07,Q3-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4186429786 -2025-07,Q3-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-07,Q3-2025,2025,CYBER_DIGITAL,Claims,720000000,710165330 -2025-07,Q3-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-07,Q3-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,151945726 -2025-07,Q3-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-07,Q3-2025,2025,CYBER_DIGITAL,Premium,1500000000,1526082375 -2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5625338665 -2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,788035102 -2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7718470017 -2025-07,Q3-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-07,Q3-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1254070661 -2025-07,Q3-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-07,Q3-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,182720137 -2025-07,Q3-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-07,Q3-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1785599790 -2025-07,Q3-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-07,Q3-2025,2025,MOTOR_TPL,Claims,3330000000,3352187263 -2025-07,Q3-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-07,Q3-2025,2025,MOTOR_TPL,ExternalCost,450000000,463458270 -2025-07,Q3-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-07,Q3-2025,2025,MOTOR_TPL,Premium,4500000000,4423057761 -2025-07,Q3-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-07,Q3-2025,2025,PADDY_CROP,Claims,1872000000,1902928672 -2025-07,Q3-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-07,Q3-2025,2025,PADDY_CROP,ExternalCost,240000000,235869422 -2025-07,Q3-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-07,Q3-2025,2025,PADDY_CROP,Premium,2400000000,2447625259 -2025-07,Q3-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-07,Q3-2025,2025,TRADE_CREDIT,Claims,1155000000,1206583167 -2025-07,Q3-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-07,Q3-2025,2025,TRADE_CREDIT,ExternalCost,210000000,214798889 -2025-07,Q3-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-07,Q3-2025,2025,TRADE_CREDIT,Premium,2100000000,2080276835 -2025-07,Q3-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-07,Q3-2025,2025,TYPHOON_FLOOD,Claims,5814000000,6005169587 -2025-07,Q3-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-07,Q3-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,558294942 -2025-07,Q3-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-07,Q3-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5786473615 -2025-08,Q3-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-08,Q3-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2586233649 -2025-08,Q3-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-08,Q3-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,422814280 -2025-08,Q3-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-08,Q3-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4256069152 -2025-08,Q3-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-08,Q3-2025,2025,CYBER_DIGITAL,Claims,720000000,736069036 -2025-08,Q3-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-08,Q3-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,145570408 -2025-08,Q3-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-08,Q3-2025,2025,CYBER_DIGITAL,Premium,1500000000,1529233984 -2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5582024886 -2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,787646592 -2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7898936490 -2025-08,Q3-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-08,Q3-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1235736544 -2025-08,Q3-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-08,Q3-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,175846630 -2025-08,Q3-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-08,Q3-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1831602960 -2025-08,Q3-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-08,Q3-2025,2025,MOTOR_TPL,Claims,3330000000,3377478778 -2025-08,Q3-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-08,Q3-2025,2025,MOTOR_TPL,ExternalCost,450000000,443853402 -2025-08,Q3-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-08,Q3-2025,2025,MOTOR_TPL,Premium,4500000000,4429266476 -2025-08,Q3-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-08,Q3-2025,2025,PADDY_CROP,Claims,1872000000,2003447501 -2025-08,Q3-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-08,Q3-2025,2025,PADDY_CROP,ExternalCost,240000000,235731801 -2025-08,Q3-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-08,Q3-2025,2025,PADDY_CROP,Premium,2400000000,2410063663 -2025-08,Q3-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-08,Q3-2025,2025,TRADE_CREDIT,Claims,1155000000,1144742113 -2025-08,Q3-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-08,Q3-2025,2025,TRADE_CREDIT,ExternalCost,210000000,209855501 -2025-08,Q3-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-08,Q3-2025,2025,TRADE_CREDIT,Premium,2100000000,2111275989 -2025-08,Q3-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-08,Q3-2025,2025,TYPHOON_FLOOD,Claims,5814000000,6837535727 -2025-08,Q3-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-08,Q3-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,556056608 -2025-08,Q3-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-08,Q3-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5792416720 -2025-09,Q3-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-09,Q3-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2500178733 -2025-09,Q3-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-09,Q3-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,407489351 -2025-09,Q3-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-09,Q3-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4187160730 -2025-09,Q3-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-09,Q3-2025,2025,CYBER_DIGITAL,Claims,720000000,735097731 -2025-09,Q3-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-09,Q3-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,147857597 -2025-09,Q3-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-09,Q3-2025,2025,CYBER_DIGITAL,Premium,1500000000,1516267153 -2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5695378980 -2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,776615748 -2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7875264043 -2025-09,Q3-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-09,Q3-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1229784581 -2025-09,Q3-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-09,Q3-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,184137549 -2025-09,Q3-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-09,Q3-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1764696218 -2025-09,Q3-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-09,Q3-2025,2025,MOTOR_TPL,Claims,3330000000,3375445253 -2025-09,Q3-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-09,Q3-2025,2025,MOTOR_TPL,ExternalCost,450000000,459034066 -2025-09,Q3-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-09,Q3-2025,2025,MOTOR_TPL,Premium,4500000000,4572707143 -2025-09,Q3-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-09,Q3-2025,2025,PADDY_CROP,Claims,1872000000,1914602631 -2025-09,Q3-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-09,Q3-2025,2025,PADDY_CROP,ExternalCost,240000000,234635215 -2025-09,Q3-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-09,Q3-2025,2025,PADDY_CROP,Premium,2400000000,2407920918 -2025-09,Q3-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-09,Q3-2025,2025,TRADE_CREDIT,Claims,1155000000,1203415890 -2025-09,Q3-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-09,Q3-2025,2025,TRADE_CREDIT,ExternalCost,210000000,213731141 -2025-09,Q3-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-09,Q3-2025,2025,TRADE_CREDIT,Premium,2100000000,2083893701 -2025-09,Q3-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-09,Q3-2025,2025,TYPHOON_FLOOD,Claims,5814000000,6663456610 -2025-09,Q3-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-09,Q3-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,560084618 -2025-09,Q3-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-09,Q3-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5782240189 -2025-10,Q4-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-10,Q4-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2465123194 -2025-10,Q4-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-10,Q4-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,427058929 -2025-10,Q4-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-10,Q4-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4157920996 -2025-10,Q4-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-10,Q4-2025,2025,CYBER_DIGITAL,Claims,720000000,721807338 -2025-10,Q4-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-10,Q4-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,151085954 -2025-10,Q4-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-10,Q4-2025,2025,CYBER_DIGITAL,Premium,1500000000,1523048082 -2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5865296943 -2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,797063547 -2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7692220642 -2025-10,Q4-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-10,Q4-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1303925789 -2025-10,Q4-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-10,Q4-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,184119295 -2025-10,Q4-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-10,Q4-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1834286834 -2025-10,Q4-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-10,Q4-2025,2025,MOTOR_TPL,Claims,3330000000,3426320775 -2025-10,Q4-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-10,Q4-2025,2025,MOTOR_TPL,ExternalCost,450000000,445469008 -2025-10,Q4-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-10,Q4-2025,2025,MOTOR_TPL,Premium,4500000000,4414461545 -2025-10,Q4-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-10,Q4-2025,2025,PADDY_CROP,Claims,1560000000,1613318945 -2025-10,Q4-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-10,Q4-2025,2025,PADDY_CROP,ExternalCost,240000000,245242522 -2025-10,Q4-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-10,Q4-2025,2025,PADDY_CROP,Premium,2400000000,2441358325 -2025-10,Q4-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-10,Q4-2025,2025,TRADE_CREDIT,Claims,1155000000,1145002848 -2025-10,Q4-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-10,Q4-2025,2025,TRADE_CREDIT,ExternalCost,210000000,213620919 -2025-10,Q4-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-10,Q4-2025,2025,TRADE_CREDIT,Premium,2100000000,2126102943 -2025-10,Q4-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-10,Q4-2025,2025,TYPHOON_FLOOD,Claims,3876000000,4030161476 -2025-10,Q4-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-10,Q4-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,582263889 -2025-10,Q4-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-10,Q4-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5610645803 -2025-11,Q4-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-11,Q4-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2609023860 -2025-11,Q4-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-11,Q4-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,418999642 -2025-11,Q4-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-11,Q4-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4153368865 -2025-11,Q4-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-11,Q4-2025,2025,CYBER_DIGITAL,Claims,720000000,744211901 -2025-11,Q4-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-11,Q4-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,147548359 -2025-11,Q4-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-11,Q4-2025,2025,CYBER_DIGITAL,Premium,1500000000,1488311452 -2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5534289351 -2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,771962659 -2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7651383304 -2025-11,Q4-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-11,Q4-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1319662422 -2025-11,Q4-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-11,Q4-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,177614550 -2025-11,Q4-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-11,Q4-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1826233412 -2025-11,Q4-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-11,Q4-2025,2025,MOTOR_TPL,Claims,3330000000,3336574322 -2025-11,Q4-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-11,Q4-2025,2025,MOTOR_TPL,ExternalCost,450000000,462991042 -2025-11,Q4-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-11,Q4-2025,2025,MOTOR_TPL,Premium,4500000000,4525466713 -2025-11,Q4-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-11,Q4-2025,2025,PADDY_CROP,Claims,1560000000,1630416795 -2025-11,Q4-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-11,Q4-2025,2025,PADDY_CROP,ExternalCost,240000000,234460921 -2025-11,Q4-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-11,Q4-2025,2025,PADDY_CROP,Premium,2400000000,2403476710 -2025-11,Q4-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-11,Q4-2025,2025,TRADE_CREDIT,Claims,1155000000,1136849666 -2025-11,Q4-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-11,Q4-2025,2025,TRADE_CREDIT,ExternalCost,210000000,215827932 -2025-11,Q4-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-11,Q4-2025,2025,TRADE_CREDIT,Premium,2100000000,2139513651 -2025-11,Q4-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-11,Q4-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3793333462 -2025-11,Q4-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-11,Q4-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,567762081 -2025-11,Q4-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-11,Q4-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5646526331 -2025-12,Q4-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, -2025-12,Q4-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2507637347 -2025-12,Q4-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2025-12,Q4-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,422676463 -2025-12,Q4-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, -2025-12,Q4-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4238395570 -2025-12,Q4-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, -2025-12,Q4-2025,2025,CYBER_DIGITAL,Claims,720000000,720587257 -2025-12,Q4-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, -2025-12,Q4-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,150689292 -2025-12,Q4-2025,2025,CYBER_DIGITAL,InternalCost,180000000, -2025-12,Q4-2025,2025,CYBER_DIGITAL,Premium,1500000000,1500685384 -2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5765963052 -2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,756679152 -2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7723473422 -2025-12,Q4-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, -2025-12,Q4-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1276475961 -2025-12,Q4-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2025-12,Q4-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,182369844 -2025-12,Q4-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, -2025-12,Q4-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1830641412 -2025-12,Q4-2025,2025,MOTOR_TPL,CapitalCost,247500000, -2025-12,Q4-2025,2025,MOTOR_TPL,Claims,3330000000,3408755434 -2025-12,Q4-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, -2025-12,Q4-2025,2025,MOTOR_TPL,ExternalCost,450000000,446333980 -2025-12,Q4-2025,2025,MOTOR_TPL,InternalCost,540000000, -2025-12,Q4-2025,2025,MOTOR_TPL,Premium,4500000000,4543551014 -2025-12,Q4-2025,2025,PADDY_CROP,CapitalCost,132000000, -2025-12,Q4-2025,2025,PADDY_CROP,Claims,1560000000,1596096863 -2025-12,Q4-2025,2025,PADDY_CROP,ExpectedProfit,120000000, -2025-12,Q4-2025,2025,PADDY_CROP,ExternalCost,240000000,237554881 -2025-12,Q4-2025,2025,PADDY_CROP,InternalCost,288000000, -2025-12,Q4-2025,2025,PADDY_CROP,Premium,2400000000,2358717486 -2025-12,Q4-2025,2025,TRADE_CREDIT,CapitalCost,115500000, -2025-12,Q4-2025,2025,TRADE_CREDIT,Claims,1155000000,1198706612 -2025-12,Q4-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, -2025-12,Q4-2025,2025,TRADE_CREDIT,ExternalCost,210000000,212768904 -2025-12,Q4-2025,2025,TRADE_CREDIT,InternalCost,252000000, -2025-12,Q4-2025,2025,TRADE_CREDIT,Premium,2100000000,2084368914 -2025-12,Q4-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, -2025-12,Q4-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3855622988 -2025-12,Q4-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, -2025-12,Q4-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,566867037 -2025-12,Q4-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, -2025-12,Q4-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5654473477 -2026-01,Q1-2026,2026,CONSTRUCTION_ENG,CapitalCost,231000000, -2026-01,Q1-2026,2026,CONSTRUCTION_ENG,Claims,2520000000,2504004089 -2026-01,Q1-2026,2026,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2026-01,Q1-2026,2026,CONSTRUCTION_ENG,ExternalCost,420000000,410607653 -2026-01,Q1-2026,2026,CONSTRUCTION_ENG,InternalCost,504000000, -2026-01,Q1-2026,2026,CONSTRUCTION_ENG,Premium,4200000000,4183603265 -2026-01,Q1-2026,2026,CYBER_DIGITAL,CapitalCost,82500000, -2026-01,Q1-2026,2026,CYBER_DIGITAL,Claims,720000000,752564947 -2026-01,Q1-2026,2026,CYBER_DIGITAL,ExpectedProfit,75000000, -2026-01,Q1-2026,2026,CYBER_DIGITAL,ExternalCost,150000000,151595862 -2026-01,Q1-2026,2026,CYBER_DIGITAL,InternalCost,180000000, -2026-01,Q1-2026,2026,CYBER_DIGITAL,Premium,1500000000,1495226780 -2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Claims,5616000000,5724058541 -2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,770684454 -2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Premium,7800000000,7925675330 -2026-01,Q1-2026,2026,MICRO_HEALTH_PA,CapitalCost,99000000, -2026-01,Q1-2026,2026,MICRO_HEALTH_PA,Claims,1260000000,1222240919 -2026-01,Q1-2026,2026,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2026-01,Q1-2026,2026,MICRO_HEALTH_PA,ExternalCost,180000000,177698668 -2026-01,Q1-2026,2026,MICRO_HEALTH_PA,InternalCost,216000000, -2026-01,Q1-2026,2026,MICRO_HEALTH_PA,Premium,1800000000,1803451479 -2026-01,Q1-2026,2026,MOTOR_TPL,CapitalCost,247500000, -2026-01,Q1-2026,2026,MOTOR_TPL,Claims,3330000000,3384607946 -2026-01,Q1-2026,2026,MOTOR_TPL,ExpectedProfit,225000000, -2026-01,Q1-2026,2026,MOTOR_TPL,ExternalCost,450000000,454177052 -2026-01,Q1-2026,2026,MOTOR_TPL,InternalCost,540000000, -2026-01,Q1-2026,2026,MOTOR_TPL,Premium,4500000000,4487379867 -2026-01,Q1-2026,2026,PADDY_CROP,CapitalCost,132000000, -2026-01,Q1-2026,2026,PADDY_CROP,Claims,1560000000,1568381543 -2026-01,Q1-2026,2026,PADDY_CROP,ExpectedProfit,120000000, -2026-01,Q1-2026,2026,PADDY_CROP,ExternalCost,240000000,235877300 -2026-01,Q1-2026,2026,PADDY_CROP,InternalCost,288000000, -2026-01,Q1-2026,2026,PADDY_CROP,Premium,2400000000,2396638866 -2026-01,Q1-2026,2026,TRADE_CREDIT,CapitalCost,115500000, -2026-01,Q1-2026,2026,TRADE_CREDIT,Claims,1155000000,1203619108 -2026-01,Q1-2026,2026,TRADE_CREDIT,ExpectedProfit,105000000, -2026-01,Q1-2026,2026,TRADE_CREDIT,ExternalCost,210000000,213729912 -2026-01,Q1-2026,2026,TRADE_CREDIT,InternalCost,252000000, -2026-01,Q1-2026,2026,TRADE_CREDIT,Premium,2100000000,2097747640 -2026-01,Q1-2026,2026,TYPHOON_FLOOD,CapitalCost,313500000, -2026-01,Q1-2026,2026,TYPHOON_FLOOD,Claims,3876000000,3786013400 -2026-01,Q1-2026,2026,TYPHOON_FLOOD,ExpectedProfit,285000000, -2026-01,Q1-2026,2026,TYPHOON_FLOOD,ExternalCost,570000000,570528459 -2026-01,Q1-2026,2026,TYPHOON_FLOOD,InternalCost,684000000, -2026-01,Q1-2026,2026,TYPHOON_FLOOD,Premium,5700000000,5624689638 -2026-02,Q1-2026,2026,CONSTRUCTION_ENG,CapitalCost,231000000, -2026-02,Q1-2026,2026,CONSTRUCTION_ENG,Claims,2520000000,2511973952 -2026-02,Q1-2026,2026,CONSTRUCTION_ENG,ExpectedProfit,210000000, -2026-02,Q1-2026,2026,CONSTRUCTION_ENG,ExternalCost,420000000,428024271 -2026-02,Q1-2026,2026,CONSTRUCTION_ENG,InternalCost,504000000, -2026-02,Q1-2026,2026,CONSTRUCTION_ENG,Premium,4200000000,4222334064 -2026-02,Q1-2026,2026,CYBER_DIGITAL,CapitalCost,82500000, -2026-02,Q1-2026,2026,CYBER_DIGITAL,Claims,720000000,737153031 -2026-02,Q1-2026,2026,CYBER_DIGITAL,ExpectedProfit,75000000, -2026-02,Q1-2026,2026,CYBER_DIGITAL,ExternalCost,150000000,147521766 -2026-02,Q1-2026,2026,CYBER_DIGITAL,InternalCost,180000000, -2026-02,Q1-2026,2026,CYBER_DIGITAL,Premium,1500000000,1515068288 -2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, -2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Claims,5616000000,5458493838 -2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, -2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,768058631 -2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,InternalCost,936000000, -2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Premium,7800000000,7706128539 -2026-02,Q1-2026,2026,MICRO_HEALTH_PA,CapitalCost,99000000, -2026-02,Q1-2026,2026,MICRO_HEALTH_PA,Claims,1260000000,1307853560 -2026-02,Q1-2026,2026,MICRO_HEALTH_PA,ExpectedProfit,90000000, -2026-02,Q1-2026,2026,MICRO_HEALTH_PA,ExternalCost,180000000,175386545 -2026-02,Q1-2026,2026,MICRO_HEALTH_PA,InternalCost,216000000, -2026-02,Q1-2026,2026,MICRO_HEALTH_PA,Premium,1800000000,1798209817 -2026-02,Q1-2026,2026,MOTOR_TPL,CapitalCost,247500000, -2026-02,Q1-2026,2026,MOTOR_TPL,Claims,3330000000,3397869497 -2026-02,Q1-2026,2026,MOTOR_TPL,ExpectedProfit,225000000, -2026-02,Q1-2026,2026,MOTOR_TPL,ExternalCost,450000000,441749751 -2026-02,Q1-2026,2026,MOTOR_TPL,InternalCost,540000000, -2026-02,Q1-2026,2026,MOTOR_TPL,Premium,4500000000,4484599382 -2026-02,Q1-2026,2026,PADDY_CROP,CapitalCost,132000000, -2026-02,Q1-2026,2026,PADDY_CROP,Claims,1560000000,1574898271 -2026-02,Q1-2026,2026,PADDY_CROP,ExpectedProfit,120000000, -2026-02,Q1-2026,2026,PADDY_CROP,ExternalCost,240000000,236313376 -2026-02,Q1-2026,2026,PADDY_CROP,InternalCost,288000000, -2026-02,Q1-2026,2026,PADDY_CROP,Premium,2400000000,2418850008 -2026-02,Q1-2026,2026,TRADE_CREDIT,CapitalCost,115500000, -2026-02,Q1-2026,2026,TRADE_CREDIT,Claims,1155000000,1120862341 -2026-02,Q1-2026,2026,TRADE_CREDIT,ExpectedProfit,105000000, -2026-02,Q1-2026,2026,TRADE_CREDIT,ExternalCost,210000000,213162152 -2026-02,Q1-2026,2026,TRADE_CREDIT,InternalCost,252000000, -2026-02,Q1-2026,2026,TRADE_CREDIT,Premium,2100000000,2113108873 -2026-02,Q1-2026,2026,TYPHOON_FLOOD,CapitalCost,313500000, -2026-02,Q1-2026,2026,TYPHOON_FLOOD,Claims,3876000000,3792770589 -2026-02,Q1-2026,2026,TYPHOON_FLOOD,ExpectedProfit,285000000, -2026-02,Q1-2026,2026,TYPHOON_FLOOD,ExternalCost,570000000,567440000 -2026-02,Q1-2026,2026,TYPHOON_FLOOD,InternalCost,684000000, -2026-02,Q1-2026,2026,TYPHOON_FLOOD,Premium,5700000000,5761570531 diff --git a/samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv b/samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv deleted file mode 100644 index 59edc7ef2..000000000 --- a/samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv +++ /dev/null @@ -1,865 +0,0 @@ -Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual -2024-09,Q3-2024,2024,COMM_FIRE,CapitalCost,2475000, -2024-09,Q3-2024,2024,COMM_FIRE,Claims,30760000,31375200 -2024-09,Q3-2024,2024,COMM_FIRE,ExpectedProfit,2250000, -2024-09,Q3-2024,2024,COMM_FIRE,ExternalCost,4500000,4590000 -2024-09,Q3-2024,2024,COMM_FIRE,InternalCost,5400000, -2024-09,Q3-2024,2024,COMM_FIRE,Premium,45000000,45900000 -2024-09,Q3-2024,2024,HOUSEHOLD,CapitalCost,4125000, -2024-09,Q3-2024,2024,HOUSEHOLD,Claims,56568065,57699426 -2024-09,Q3-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, -2024-09,Q3-2024,2024,HOUSEHOLD,ExternalCost,7500000,7650000 -2024-09,Q3-2024,2024,HOUSEHOLD,InternalCost,9000000, -2024-09,Q3-2024,2024,HOUSEHOLD,Premium,78750000,80325000 -2024-09,Q3-2024,2024,LIABILITY,CapitalCost,2090000, -2024-09,Q3-2024,2024,LIABILITY,Claims,23940000,24418800 -2024-09,Q3-2024,2024,LIABILITY,ExpectedProfit,1900000, -2024-09,Q3-2024,2024,LIABILITY,ExternalCost,3800000,3876000 -2024-09,Q3-2024,2024,LIABILITY,InternalCost,4560000, -2024-09,Q3-2024,2024,LIABILITY,Premium,38000000,38760000 -2024-09,Q3-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, -2024-09,Q3-2024,2024,LIFE_HEALTH_EU,Claims,27840000,28396800 -2024-09,Q3-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2024-09,Q3-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,4896000 -2024-09,Q3-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, -2024-09,Q3-2024,2024,LIFE_HEALTH_EU,Premium,48000000,48960000 -2024-09,Q3-2024,2024,MOTOR,CapitalCost,3025000, -2024-09,Q3-2024,2024,MOTOR,Claims,40577778,41389334 -2024-09,Q3-2024,2024,MOTOR,ExpectedProfit,2750000, -2024-09,Q3-2024,2024,MOTOR,ExternalCost,5500000,5610000 -2024-09,Q3-2024,2024,MOTOR,InternalCost,6600000, -2024-09,Q3-2024,2024,MOTOR,Premium,55000000,56100000 -2024-09,Q3-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, -2024-09,Q3-2024,2024,SPECIALTY_AVTN,Claims,15750000,16065000 -2024-09,Q3-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, -2024-09,Q3-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2550000 -2024-09,Q3-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, -2024-09,Q3-2024,2024,SPECIALTY_AVTN,Premium,25000000,25500000 -2024-09,Q3-2024,2024,TECH_RISK,CapitalCost,1760000, -2024-09,Q3-2024,2024,TECH_RISK,Claims,15273244,15578709 -2024-09,Q3-2024,2024,TECH_RISK,ExpectedProfit,1600000, -2024-09,Q3-2024,2024,TECH_RISK,ExternalCost,3200000,3264000 -2024-09,Q3-2024,2024,TECH_RISK,InternalCost,3840000, -2024-09,Q3-2024,2024,TECH_RISK,Premium,32000000,32640000 -2024-09,Q3-2024,2024,TRANSPORT,CapitalCost,1210000, -2024-09,Q3-2024,2024,TRANSPORT,Claims,14774222,15069706 -2024-09,Q3-2024,2024,TRANSPORT,ExpectedProfit,1100000, -2024-09,Q3-2024,2024,TRANSPORT,ExternalCost,2200000,2244000 -2024-09,Q3-2024,2024,TRANSPORT,InternalCost,2640000, -2024-09,Q3-2024,2024,TRANSPORT,Premium,22000000,22440000 -2024-10,Q4-2024,2024,COMM_FIRE,CapitalCost,2475000, -2024-10,Q4-2024,2024,COMM_FIRE,Claims,27250000,26432500 -2024-10,Q4-2024,2024,COMM_FIRE,ExpectedProfit,2250000, -2024-10,Q4-2024,2024,COMM_FIRE,ExternalCost,4500000,4365000 -2024-10,Q4-2024,2024,COMM_FIRE,InternalCost,5400000, -2024-10,Q4-2024,2024,COMM_FIRE,Premium,45000000,43650000 -2024-10,Q4-2024,2024,HOUSEHOLD,CapitalCost,4125000, -2024-10,Q4-2024,2024,HOUSEHOLD,Claims,52717205,51135689 -2024-10,Q4-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, -2024-10,Q4-2024,2024,HOUSEHOLD,ExternalCost,7500000,7275000 -2024-10,Q4-2024,2024,HOUSEHOLD,InternalCost,9000000, -2024-10,Q4-2024,2024,HOUSEHOLD,Premium,75000000,72750000 -2024-10,Q4-2024,2024,LIABILITY,CapitalCost,2090000, -2024-10,Q4-2024,2024,LIABILITY,Claims,23940000,23221800 -2024-10,Q4-2024,2024,LIABILITY,ExpectedProfit,1900000, -2024-10,Q4-2024,2024,LIABILITY,ExternalCost,3800000,3686000 -2024-10,Q4-2024,2024,LIABILITY,InternalCost,4560000, -2024-10,Q4-2024,2024,LIABILITY,Premium,38000000,36860000 -2024-10,Q4-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, -2024-10,Q4-2024,2024,LIFE_HEALTH_EU,Claims,27840000,27004800 -2024-10,Q4-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2024-10,Q4-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,4656000 -2024-10,Q4-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, -2024-10,Q4-2024,2024,LIFE_HEALTH_EU,Premium,48000000,46560000 -2024-10,Q4-2024,2024,MOTOR,CapitalCost,3025000, -2024-10,Q4-2024,2024,MOTOR,Claims,39081778,37909325 -2024-10,Q4-2024,2024,MOTOR,ExpectedProfit,2750000, -2024-10,Q4-2024,2024,MOTOR,ExternalCost,5500000,5335000 -2024-10,Q4-2024,2024,MOTOR,InternalCost,6600000, -2024-10,Q4-2024,2024,MOTOR,Premium,55000000,53350000 -2024-10,Q4-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, -2024-10,Q4-2024,2024,SPECIALTY_AVTN,Claims,15750000,15277500 -2024-10,Q4-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, -2024-10,Q4-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2425000 -2024-10,Q4-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, -2024-10,Q4-2024,2024,SPECIALTY_AVTN,Premium,25000000,24250000 -2024-10,Q4-2024,2024,TECH_RISK,CapitalCost,1760000, -2024-10,Q4-2024,2024,TECH_RISK,Claims,16860444,16354631 -2024-10,Q4-2024,2024,TECH_RISK,ExpectedProfit,1600000, -2024-10,Q4-2024,2024,TECH_RISK,ExternalCost,3200000,3104000 -2024-10,Q4-2024,2024,TECH_RISK,InternalCost,3840000, -2024-10,Q4-2024,2024,TECH_RISK,Premium,32000000,31040000 -2024-10,Q4-2024,2024,TRANSPORT,CapitalCost,1210000, -2024-10,Q4-2024,2024,TRANSPORT,Claims,15390222,14928515 -2024-10,Q4-2024,2024,TRANSPORT,ExpectedProfit,1100000, -2024-10,Q4-2024,2024,TRANSPORT,ExternalCost,2200000,2134000 -2024-10,Q4-2024,2024,TRANSPORT,InternalCost,2640000, -2024-10,Q4-2024,2024,TRANSPORT,Premium,22000000,21340000 -2024-11,Q4-2024,2024,COMM_FIRE,CapitalCost,2475000, -2024-11,Q4-2024,2024,COMM_FIRE,Claims,26080000,27384000 -2024-11,Q4-2024,2024,COMM_FIRE,ExpectedProfit,2250000, -2024-11,Q4-2024,2024,COMM_FIRE,ExternalCost,4500000,4725000 -2024-11,Q4-2024,2024,COMM_FIRE,InternalCost,5400000, -2024-11,Q4-2024,2024,COMM_FIRE,Premium,45000000,47250000 -2024-11,Q4-2024,2024,HOUSEHOLD,CapitalCost,4125000, -2024-11,Q4-2024,2024,HOUSEHOLD,Claims,47246345,49608662 -2024-11,Q4-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, -2024-11,Q4-2024,2024,HOUSEHOLD,ExternalCost,7500000,7875000 -2024-11,Q4-2024,2024,HOUSEHOLD,InternalCost,9000000, -2024-11,Q4-2024,2024,HOUSEHOLD,Premium,71250000,74812500 -2024-11,Q4-2024,2024,LIABILITY,CapitalCost,2090000, -2024-11,Q4-2024,2024,LIABILITY,Claims,23940000,25137000 -2024-11,Q4-2024,2024,LIABILITY,ExpectedProfit,1900000, -2024-11,Q4-2024,2024,LIABILITY,ExternalCost,3800000,3990000 -2024-11,Q4-2024,2024,LIABILITY,InternalCost,4560000, -2024-11,Q4-2024,2024,LIABILITY,Premium,38000000,39900000 -2024-11,Q4-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, -2024-11,Q4-2024,2024,LIFE_HEALTH_EU,Claims,27840000,29232000 -2024-11,Q4-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2024-11,Q4-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,5040000 -2024-11,Q4-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, -2024-11,Q4-2024,2024,LIFE_HEALTH_EU,Premium,48000000,50400000 -2024-11,Q4-2024,2024,MOTOR,CapitalCost,3025000, -2024-11,Q4-2024,2024,MOTOR,Claims,37585778,39465067 -2024-11,Q4-2024,2024,MOTOR,ExpectedProfit,2750000, -2024-11,Q4-2024,2024,MOTOR,ExternalCost,5500000,5775000 -2024-11,Q4-2024,2024,MOTOR,InternalCost,6600000, -2024-11,Q4-2024,2024,MOTOR,Premium,55000000,57750000 -2024-11,Q4-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, -2024-11,Q4-2024,2024,SPECIALTY_AVTN,Claims,15750000,16537500 -2024-11,Q4-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, -2024-11,Q4-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2625000 -2024-11,Q4-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, -2024-11,Q4-2024,2024,SPECIALTY_AVTN,Premium,25000000,26250000 -2024-11,Q4-2024,2024,TECH_RISK,CapitalCost,1760000, -2024-11,Q4-2024,2024,TECH_RISK,Claims,17654044,18536746 -2024-11,Q4-2024,2024,TECH_RISK,ExpectedProfit,1600000, -2024-11,Q4-2024,2024,TECH_RISK,ExternalCost,3200000,3360000 -2024-11,Q4-2024,2024,TECH_RISK,InternalCost,3840000, -2024-11,Q4-2024,2024,TECH_RISK,Premium,32000000,33600000 -2024-11,Q4-2024,2024,TRANSPORT,CapitalCost,1210000, -2024-11,Q4-2024,2024,TRANSPORT,Claims,16006222,16806533 -2024-11,Q4-2024,2024,TRANSPORT,ExpectedProfit,1100000, -2024-11,Q4-2024,2024,TRANSPORT,ExternalCost,2200000,2310000 -2024-11,Q4-2024,2024,TRANSPORT,InternalCost,2640000, -2024-11,Q4-2024,2024,TRANSPORT,Premium,22000000,23100000 -2024-12,Q4-2024,2024,COMM_FIRE,CapitalCost,2475000, -2024-12,Q4-2024,2024,COMM_FIRE,Claims,28420000,27851600 -2024-12,Q4-2024,2024,COMM_FIRE,ExpectedProfit,2250000, -2024-12,Q4-2024,2024,COMM_FIRE,ExternalCost,4500000,4410000 -2024-12,Q4-2024,2024,COMM_FIRE,InternalCost,5400000, -2024-12,Q4-2024,2024,COMM_FIRE,Premium,45000000,44100000 -2024-12,Q4-2024,2024,HOUSEHOLD,CapitalCost,4125000, -2024-12,Q4-2024,2024,HOUSEHOLD,Claims,48255484,47290374 -2024-12,Q4-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, -2024-12,Q4-2024,2024,HOUSEHOLD,ExternalCost,7500000,7350000 -2024-12,Q4-2024,2024,HOUSEHOLD,InternalCost,9000000, -2024-12,Q4-2024,2024,HOUSEHOLD,Premium,67500000,66150000 -2024-12,Q4-2024,2024,LIABILITY,CapitalCost,2090000, -2024-12,Q4-2024,2024,LIABILITY,Claims,23940000,23461200 -2024-12,Q4-2024,2024,LIABILITY,ExpectedProfit,1900000, -2024-12,Q4-2024,2024,LIABILITY,ExternalCost,3800000,3724000 -2024-12,Q4-2024,2024,LIABILITY,InternalCost,4560000, -2024-12,Q4-2024,2024,LIABILITY,Premium,38000000,37240000 -2024-12,Q4-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, -2024-12,Q4-2024,2024,LIFE_HEALTH_EU,Claims,27840000,27283200 -2024-12,Q4-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2024-12,Q4-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,4704000 -2024-12,Q4-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, -2024-12,Q4-2024,2024,LIFE_HEALTH_EU,Premium,48000000,47040000 -2024-12,Q4-2024,2024,MOTOR,CapitalCost,3025000, -2024-12,Q4-2024,2024,MOTOR,Claims,36089778,35367982 -2024-12,Q4-2024,2024,MOTOR,ExpectedProfit,2750000, -2024-12,Q4-2024,2024,MOTOR,ExternalCost,5500000,5390000 -2024-12,Q4-2024,2024,MOTOR,InternalCost,6600000, -2024-12,Q4-2024,2024,MOTOR,Premium,55000000,53900000 -2024-12,Q4-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, -2024-12,Q4-2024,2024,SPECIALTY_AVTN,Claims,15750000,15435000 -2024-12,Q4-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, -2024-12,Q4-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2450000 -2024-12,Q4-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, -2024-12,Q4-2024,2024,SPECIALTY_AVTN,Premium,25000000,24500000 -2024-12,Q4-2024,2024,TECH_RISK,CapitalCost,1760000, -2024-12,Q4-2024,2024,TECH_RISK,Claims,20034844,19634147 -2024-12,Q4-2024,2024,TECH_RISK,ExpectedProfit,1600000, -2024-12,Q4-2024,2024,TECH_RISK,ExternalCost,3200000,3136000 -2024-12,Q4-2024,2024,TECH_RISK,InternalCost,3840000, -2024-12,Q4-2024,2024,TECH_RISK,Premium,32000000,31360000 -2024-12,Q4-2024,2024,TRANSPORT,CapitalCost,1210000, -2024-12,Q4-2024,2024,TRANSPORT,Claims,16622222,16289778 -2024-12,Q4-2024,2024,TRANSPORT,ExpectedProfit,1100000, -2024-12,Q4-2024,2024,TRANSPORT,ExternalCost,2200000,2156000 -2024-12,Q4-2024,2024,TRANSPORT,InternalCost,2640000, -2024-12,Q4-2024,2024,TRANSPORT,Premium,22000000,21560000 -2025-01,Q1-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-01,Q1-2025,2025,COMM_FIRE,Claims,28420000,28704200 -2025-01,Q1-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-01,Q1-2025,2025,COMM_FIRE,ExternalCost,4500000,4545000 -2025-01,Q1-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-01,Q1-2025,2025,COMM_FIRE,Premium,45000000,45450000 -2025-01,Q1-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-01,Q1-2025,2025,HOUSEHOLD,Claims,48866345,49355008 -2025-01,Q1-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-01,Q1-2025,2025,HOUSEHOLD,ExternalCost,7500000,7575000 -2025-01,Q1-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-01,Q1-2025,2025,HOUSEHOLD,Premium,71250000,71962500 -2025-01,Q1-2025,2025,LIABILITY,CapitalCost,2090000, -2025-01,Q1-2025,2025,LIABILITY,Claims,23940000,24179400 -2025-01,Q1-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-01,Q1-2025,2025,LIABILITY,ExternalCost,3800000,3838000 -2025-01,Q1-2025,2025,LIABILITY,InternalCost,4560000, -2025-01,Q1-2025,2025,LIABILITY,Premium,38000000,38380000 -2025-01,Q1-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-01,Q1-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28118400 -2025-01,Q1-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-01,Q1-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4848000 -2025-01,Q1-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-01,Q1-2025,2025,LIFE_HEALTH_EU,Premium,48000000,48480000 -2025-01,Q1-2025,2025,MOTOR,CapitalCost,3025000, -2025-01,Q1-2025,2025,MOTOR,Claims,36089778,36450676 -2025-01,Q1-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-01,Q1-2025,2025,MOTOR,ExternalCost,5500000,5555000 -2025-01,Q1-2025,2025,MOTOR,InternalCost,6600000, -2025-01,Q1-2025,2025,MOTOR,Premium,55000000,55550000 -2025-01,Q1-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-01,Q1-2025,2025,SPECIALTY_AVTN,Claims,15750000,15907500 -2025-01,Q1-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-01,Q1-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2525000 -2025-01,Q1-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-01,Q1-2025,2025,SPECIALTY_AVTN,Premium,25000000,25250000 -2025-01,Q1-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-01,Q1-2025,2025,TECH_RISK,Claims,18447644,18632120 -2025-01,Q1-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-01,Q1-2025,2025,TECH_RISK,ExternalCost,3200000,3232000 -2025-01,Q1-2025,2025,TECH_RISK,InternalCost,3840000, -2025-01,Q1-2025,2025,TECH_RISK,Premium,32000000,32320000 -2025-01,Q1-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-01,Q1-2025,2025,TRANSPORT,Claims,15390222,15544124 -2025-01,Q1-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-01,Q1-2025,2025,TRANSPORT,ExternalCost,2200000,2222000 -2025-01,Q1-2025,2025,TRANSPORT,InternalCost,2640000, -2025-01,Q1-2025,2025,TRANSPORT,Premium,22000000,22220000 -2025-02,Q1-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-02,Q1-2025,2025,COMM_FIRE,Claims,27250000,26160000 -2025-02,Q1-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-02,Q1-2025,2025,COMM_FIRE,ExternalCost,4500000,4320000 -2025-02,Q1-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-02,Q1-2025,2025,COMM_FIRE,Premium,45000000,43200000 -2025-02,Q1-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-02,Q1-2025,2025,HOUSEHOLD,Claims,46879829,45004636 -2025-02,Q1-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-02,Q1-2025,2025,HOUSEHOLD,ExternalCost,7500000,7200000 -2025-02,Q1-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-02,Q1-2025,2025,HOUSEHOLD,Premium,69000000,66240000 -2025-02,Q1-2025,2025,LIABILITY,CapitalCost,2090000, -2025-02,Q1-2025,2025,LIABILITY,Claims,23940000,22982400 -2025-02,Q1-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-02,Q1-2025,2025,LIABILITY,ExternalCost,3800000,3648000 -2025-02,Q1-2025,2025,LIABILITY,InternalCost,4560000, -2025-02,Q1-2025,2025,LIABILITY,Premium,38000000,36480000 -2025-02,Q1-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-02,Q1-2025,2025,LIFE_HEALTH_EU,Claims,27840000,26726400 -2025-02,Q1-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-02,Q1-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4608000 -2025-02,Q1-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-02,Q1-2025,2025,LIFE_HEALTH_EU,Premium,48000000,46080000 -2025-02,Q1-2025,2025,MOTOR,CapitalCost,3025000, -2025-02,Q1-2025,2025,MOTOR,Claims,34593778,33210027 -2025-02,Q1-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-02,Q1-2025,2025,MOTOR,ExternalCost,5500000,5280000 -2025-02,Q1-2025,2025,MOTOR,InternalCost,6600000, -2025-02,Q1-2025,2025,MOTOR,Premium,55000000,52800000 -2025-02,Q1-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-02,Q1-2025,2025,SPECIALTY_AVTN,Claims,15750000,15120000 -2025-02,Q1-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-02,Q1-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2400000 -2025-02,Q1-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-02,Q1-2025,2025,SPECIALTY_AVTN,Premium,25000000,24000000 -2025-02,Q1-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-02,Q1-2025,2025,TECH_RISK,Claims,16860444,16186026 -2025-02,Q1-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-02,Q1-2025,2025,TECH_RISK,ExternalCost,3200000,3072000 -2025-02,Q1-2025,2025,TECH_RISK,InternalCost,3840000, -2025-02,Q1-2025,2025,TECH_RISK,Premium,32000000,30720000 -2025-02,Q1-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-02,Q1-2025,2025,TRANSPORT,Claims,14774222,14183253 -2025-02,Q1-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-02,Q1-2025,2025,TRANSPORT,ExternalCost,2200000,2112000 -2025-02,Q1-2025,2025,TRANSPORT,InternalCost,2640000, -2025-02,Q1-2025,2025,TRANSPORT,Premium,22000000,21120000 -2025-03,Q1-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-03,Q1-2025,2025,COMM_FIRE,Claims,24910000,25657300 -2025-03,Q1-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-03,Q1-2025,2025,COMM_FIRE,ExternalCost,4500000,4635000 -2025-03,Q1-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-03,Q1-2025,2025,COMM_FIRE,Premium,45000000,46350000 -2025-03,Q1-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-03,Q1-2025,2025,HOUSEHOLD,Claims,42997205,44287121 -2025-03,Q1-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-03,Q1-2025,2025,HOUSEHOLD,ExternalCost,7500000,7725000 -2025-03,Q1-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-03,Q1-2025,2025,HOUSEHOLD,Premium,75000000,77250000 -2025-03,Q1-2025,2025,LIABILITY,CapitalCost,2090000, -2025-03,Q1-2025,2025,LIABILITY,Claims,23940000,24658200 -2025-03,Q1-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-03,Q1-2025,2025,LIABILITY,ExternalCost,3800000,3914000 -2025-03,Q1-2025,2025,LIABILITY,InternalCost,4560000, -2025-03,Q1-2025,2025,LIABILITY,Premium,38000000,39140000 -2025-03,Q1-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-03,Q1-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28675200 -2025-03,Q1-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-03,Q1-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4944000 -2025-03,Q1-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-03,Q1-2025,2025,LIFE_HEALTH_EU,Premium,48000000,49440000 -2025-03,Q1-2025,2025,MOTOR,CapitalCost,3025000, -2025-03,Q1-2025,2025,MOTOR,Claims,37585778,38713351 -2025-03,Q1-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-03,Q1-2025,2025,MOTOR,ExternalCost,5500000,5665000 -2025-03,Q1-2025,2025,MOTOR,InternalCost,6600000, -2025-03,Q1-2025,2025,MOTOR,Premium,55000000,56650000 -2025-03,Q1-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-03,Q1-2025,2025,SPECIALTY_AVTN,Claims,15750000,16222500 -2025-03,Q1-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-03,Q1-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2575000 -2025-03,Q1-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-03,Q1-2025,2025,SPECIALTY_AVTN,Premium,25000000,25750000 -2025-03,Q1-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-03,Q1-2025,2025,TECH_RISK,Claims,15273244,15731441 -2025-03,Q1-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-03,Q1-2025,2025,TECH_RISK,ExternalCost,3200000,3296000 -2025-03,Q1-2025,2025,TECH_RISK,InternalCost,3840000, -2025-03,Q1-2025,2025,TECH_RISK,Premium,32000000,32960000 -2025-03,Q1-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-03,Q1-2025,2025,TRANSPORT,Claims,13542222,13948489 -2025-03,Q1-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-03,Q1-2025,2025,TRANSPORT,ExternalCost,2200000,2266000 -2025-03,Q1-2025,2025,TRANSPORT,InternalCost,2640000, -2025-03,Q1-2025,2025,TRANSPORT,Premium,22000000,22660000 -2025-04,Q2-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-04,Q2-2025,2025,COMM_FIRE,Claims,23740000,23502600 -2025-04,Q2-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-04,Q2-2025,2025,COMM_FIRE,ExternalCost,4500000,4455000 -2025-04,Q2-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-04,Q2-2025,2025,COMM_FIRE,Premium,45000000,44550000 -2025-04,Q2-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-04,Q2-2025,2025,HOUSEHOLD,Claims,41621549,41205334 -2025-04,Q2-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-04,Q2-2025,2025,HOUSEHOLD,ExternalCost,7500000,7425000 -2025-04,Q2-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-04,Q2-2025,2025,HOUSEHOLD,Premium,76500000,75735000 -2025-04,Q2-2025,2025,LIABILITY,CapitalCost,2090000, -2025-04,Q2-2025,2025,LIABILITY,Claims,23940000,23700600 -2025-04,Q2-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-04,Q2-2025,2025,LIABILITY,ExternalCost,3800000,3762000 -2025-04,Q2-2025,2025,LIABILITY,InternalCost,4560000, -2025-04,Q2-2025,2025,LIABILITY,Premium,38000000,37620000 -2025-04,Q2-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-04,Q2-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27561600 -2025-04,Q2-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-04,Q2-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4752000 -2025-04,Q2-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-04,Q2-2025,2025,LIFE_HEALTH_EU,Premium,48000000,47520000 -2025-04,Q2-2025,2025,MOTOR,CapitalCost,3025000, -2025-04,Q2-2025,2025,MOTOR,Claims,39081778,38690960 -2025-04,Q2-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-04,Q2-2025,2025,MOTOR,ExternalCost,5500000,5445000 -2025-04,Q2-2025,2025,MOTOR,InternalCost,6600000, -2025-04,Q2-2025,2025,MOTOR,Premium,55000000,54450000 -2025-04,Q2-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-04,Q2-2025,2025,SPECIALTY_AVTN,Claims,15750000,15592500 -2025-04,Q2-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-04,Q2-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2475000 -2025-04,Q2-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-04,Q2-2025,2025,SPECIALTY_AVTN,Premium,25000000,24750000 -2025-04,Q2-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-04,Q2-2025,2025,TECH_RISK,Claims,13686044,13549184 -2025-04,Q2-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-04,Q2-2025,2025,TECH_RISK,ExternalCost,3200000,3168000 -2025-04,Q2-2025,2025,TECH_RISK,InternalCost,3840000, -2025-04,Q2-2025,2025,TECH_RISK,Premium,32000000,31680000 -2025-04,Q2-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-04,Q2-2025,2025,TRANSPORT,Claims,12926222,12796960 -2025-04,Q2-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-04,Q2-2025,2025,TRANSPORT,ExternalCost,2200000,2178000 -2025-04,Q2-2025,2025,TRANSPORT,InternalCost,2640000, -2025-04,Q2-2025,2025,TRANSPORT,Premium,22000000,21780000 -2025-05,Q2-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-05,Q2-2025,2025,COMM_FIRE,Claims,24910000,25906400 -2025-05,Q2-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-05,Q2-2025,2025,COMM_FIRE,ExternalCost,4500000,4680000 -2025-05,Q2-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-05,Q2-2025,2025,COMM_FIRE,Premium,45000000,46800000 -2025-05,Q2-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-05,Q2-2025,2025,HOUSEHOLD,Claims,40368065,41982788 -2025-05,Q2-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-05,Q2-2025,2025,HOUSEHOLD,ExternalCost,7500000,7800000 -2025-05,Q2-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-05,Q2-2025,2025,HOUSEHOLD,Premium,78750000,81900000 -2025-05,Q2-2025,2025,LIABILITY,CapitalCost,2090000, -2025-05,Q2-2025,2025,LIABILITY,Claims,23940000,24897600 -2025-05,Q2-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-05,Q2-2025,2025,LIABILITY,ExternalCost,3800000,3952000 -2025-05,Q2-2025,2025,LIABILITY,InternalCost,4560000, -2025-05,Q2-2025,2025,LIABILITY,Premium,38000000,39520000 -2025-05,Q2-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-05,Q2-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28953600 -2025-05,Q2-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-05,Q2-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4992000 -2025-05,Q2-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-05,Q2-2025,2025,LIFE_HEALTH_EU,Premium,48000000,49920000 -2025-05,Q2-2025,2025,MOTOR,CapitalCost,3025000, -2025-05,Q2-2025,2025,MOTOR,Claims,40577778,42200889 -2025-05,Q2-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-05,Q2-2025,2025,MOTOR,ExternalCost,5500000,5720000 -2025-05,Q2-2025,2025,MOTOR,InternalCost,6600000, -2025-05,Q2-2025,2025,MOTOR,Premium,55000000,57200000 -2025-05,Q2-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-05,Q2-2025,2025,SPECIALTY_AVTN,Claims,15750000,16380000 -2025-05,Q2-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-05,Q2-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2600000 -2025-05,Q2-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-05,Q2-2025,2025,SPECIALTY_AVTN,Premium,25000000,26000000 -2025-05,Q2-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-05,Q2-2025,2025,TECH_RISK,Claims,14479644,15058830 -2025-05,Q2-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-05,Q2-2025,2025,TECH_RISK,ExternalCost,3200000,3328000 -2025-05,Q2-2025,2025,TECH_RISK,InternalCost,3840000, -2025-05,Q2-2025,2025,TECH_RISK,Premium,32000000,33280000 -2025-05,Q2-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-05,Q2-2025,2025,TRANSPORT,Claims,12310222,12802631 -2025-05,Q2-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-05,Q2-2025,2025,TRANSPORT,ExternalCost,2200000,2288000 -2025-05,Q2-2025,2025,TRANSPORT,InternalCost,2640000, -2025-05,Q2-2025,2025,TRANSPORT,Premium,22000000,22880000 -2025-06,Q2-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-06,Q2-2025,2025,COMM_FIRE,Claims,29590000,28110500 -2025-06,Q2-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-06,Q2-2025,2025,COMM_FIRE,ExternalCost,4500000,4275000 -2025-06,Q2-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-06,Q2-2025,2025,COMM_FIRE,Premium,45000000,42750000 -2025-06,Q2-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-06,Q2-2025,2025,HOUSEHOLD,Claims,42354581,40236852 -2025-06,Q2-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-06,Q2-2025,2025,HOUSEHOLD,ExternalCost,7500000,7125000 -2025-06,Q2-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-06,Q2-2025,2025,HOUSEHOLD,Premium,81000000,76950000 -2025-06,Q2-2025,2025,LIABILITY,CapitalCost,2090000, -2025-06,Q2-2025,2025,LIABILITY,Claims,23940000,22743000 -2025-06,Q2-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-06,Q2-2025,2025,LIABILITY,ExternalCost,3800000,3610000 -2025-06,Q2-2025,2025,LIABILITY,InternalCost,4560000, -2025-06,Q2-2025,2025,LIABILITY,Premium,38000000,36100000 -2025-06,Q2-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-06,Q2-2025,2025,LIFE_HEALTH_EU,Claims,27840000,26448000 -2025-06,Q2-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-06,Q2-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4560000 -2025-06,Q2-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-06,Q2-2025,2025,LIFE_HEALTH_EU,Premium,48000000,45600000 -2025-06,Q2-2025,2025,MOTOR,CapitalCost,3025000, -2025-06,Q2-2025,2025,MOTOR,Claims,42073778,39970089 -2025-06,Q2-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-06,Q2-2025,2025,MOTOR,ExternalCost,5500000,5225000 -2025-06,Q2-2025,2025,MOTOR,InternalCost,6600000, -2025-06,Q2-2025,2025,MOTOR,Premium,55000000,52250000 -2025-06,Q2-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-06,Q2-2025,2025,SPECIALTY_AVTN,Claims,15750000,14962500 -2025-06,Q2-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-06,Q2-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2375000 -2025-06,Q2-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-06,Q2-2025,2025,SPECIALTY_AVTN,Premium,25000000,23750000 -2025-06,Q2-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-06,Q2-2025,2025,TECH_RISK,Claims,15273244,14509582 -2025-06,Q2-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-06,Q2-2025,2025,TECH_RISK,ExternalCost,3200000,3040000 -2025-06,Q2-2025,2025,TECH_RISK,InternalCost,3840000, -2025-06,Q2-2025,2025,TECH_RISK,Premium,32000000,30400000 -2025-06,Q2-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-06,Q2-2025,2025,TRANSPORT,Claims,12926222,12279911 -2025-06,Q2-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-06,Q2-2025,2025,TRANSPORT,ExternalCost,2200000,2090000 -2025-06,Q2-2025,2025,TRANSPORT,InternalCost,2640000, -2025-06,Q2-2025,2025,TRANSPORT,Premium,22000000,20900000 -2025-07,Q3-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-07,Q3-2025,2025,COMM_FIRE,Claims,30760000,32605600 -2025-07,Q3-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-07,Q3-2025,2025,COMM_FIRE,ExternalCost,4500000,4770000 -2025-07,Q3-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-07,Q3-2025,2025,COMM_FIRE,Premium,45000000,47700000 -2025-07,Q3-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-07,Q3-2025,2025,HOUSEHOLD,Claims,47458925,50306460 -2025-07,Q3-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-07,Q3-2025,2025,HOUSEHOLD,ExternalCost,7500000,7950000 -2025-07,Q3-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-07,Q3-2025,2025,HOUSEHOLD,Premium,82500000,87450000 -2025-07,Q3-2025,2025,LIABILITY,CapitalCost,2090000, -2025-07,Q3-2025,2025,LIABILITY,Claims,23940000,25376400 -2025-07,Q3-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-07,Q3-2025,2025,LIABILITY,ExternalCost,3800000,4028000 -2025-07,Q3-2025,2025,LIABILITY,InternalCost,4560000, -2025-07,Q3-2025,2025,LIABILITY,Premium,38000000,40280000 -2025-07,Q3-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-07,Q3-2025,2025,LIFE_HEALTH_EU,Claims,27840000,29510400 -2025-07,Q3-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-07,Q3-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,5088000 -2025-07,Q3-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-07,Q3-2025,2025,LIFE_HEALTH_EU,Premium,48000000,50880000 -2025-07,Q3-2025,2025,MOTOR,CapitalCost,3025000, -2025-07,Q3-2025,2025,MOTOR,Claims,43569778,46183965 -2025-07,Q3-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-07,Q3-2025,2025,MOTOR,ExternalCost,5500000,5830000 -2025-07,Q3-2025,2025,MOTOR,InternalCost,6600000, -2025-07,Q3-2025,2025,MOTOR,Premium,55000000,58300000 -2025-07,Q3-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-07,Q3-2025,2025,SPECIALTY_AVTN,Claims,15750000,16695000 -2025-07,Q3-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-07,Q3-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2650000 -2025-07,Q3-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-07,Q3-2025,2025,SPECIALTY_AVTN,Premium,25000000,26500000 -2025-07,Q3-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-07,Q3-2025,2025,TECH_RISK,Claims,16066844,17030855 -2025-07,Q3-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-07,Q3-2025,2025,TECH_RISK,ExternalCost,3200000,3392000 -2025-07,Q3-2025,2025,TECH_RISK,InternalCost,3840000, -2025-07,Q3-2025,2025,TECH_RISK,Premium,32000000,33920000 -2025-07,Q3-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-07,Q3-2025,2025,TRANSPORT,Claims,13542222,14354755 -2025-07,Q3-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-07,Q3-2025,2025,TRANSPORT,ExternalCost,2200000,2332000 -2025-07,Q3-2025,2025,TRANSPORT,InternalCost,2640000, -2025-07,Q3-2025,2025,TRANSPORT,Premium,22000000,23320000 -2025-08,Q3-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-08,Q3-2025,2025,COMM_FIRE,Claims,31930000,31291400 -2025-08,Q3-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-08,Q3-2025,2025,COMM_FIRE,ExternalCost,4500000,4410000 -2025-08,Q3-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-08,Q3-2025,2025,COMM_FIRE,Premium,45000000,44100000 -2025-08,Q3-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-08,Q3-2025,2025,HOUSEHOLD,Claims,52074581,51033089 -2025-08,Q3-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-08,Q3-2025,2025,HOUSEHOLD,ExternalCost,7500000,7350000 -2025-08,Q3-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-08,Q3-2025,2025,HOUSEHOLD,Premium,81000000,79380000 -2025-08,Q3-2025,2025,LIABILITY,CapitalCost,2090000, -2025-08,Q3-2025,2025,LIABILITY,Claims,23940000,23461200 -2025-08,Q3-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-08,Q3-2025,2025,LIABILITY,ExternalCost,3800000,3724000 -2025-08,Q3-2025,2025,LIABILITY,InternalCost,4560000, -2025-08,Q3-2025,2025,LIABILITY,Premium,38000000,37240000 -2025-08,Q3-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-08,Q3-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27283200 -2025-08,Q3-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-08,Q3-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4704000 -2025-08,Q3-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-08,Q3-2025,2025,LIFE_HEALTH_EU,Premium,48000000,47040000 -2025-08,Q3-2025,2025,MOTOR,CapitalCost,3025000, -2025-08,Q3-2025,2025,MOTOR,Claims,42073778,41232302 -2025-08,Q3-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-08,Q3-2025,2025,MOTOR,ExternalCost,5500000,5390000 -2025-08,Q3-2025,2025,MOTOR,InternalCost,6600000, -2025-08,Q3-2025,2025,MOTOR,Premium,55000000,53900000 -2025-08,Q3-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-08,Q3-2025,2025,SPECIALTY_AVTN,Claims,15750000,15435000 -2025-08,Q3-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-08,Q3-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2450000 -2025-08,Q3-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-08,Q3-2025,2025,SPECIALTY_AVTN,Premium,25000000,24500000 -2025-08,Q3-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-08,Q3-2025,2025,TECH_RISK,Claims,14479644,14190051 -2025-08,Q3-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-08,Q3-2025,2025,TECH_RISK,ExternalCost,3200000,3136000 -2025-08,Q3-2025,2025,TECH_RISK,InternalCost,3840000, -2025-08,Q3-2025,2025,TECH_RISK,Premium,32000000,31360000 -2025-08,Q3-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-08,Q3-2025,2025,TRANSPORT,Claims,14158222,13875058 -2025-08,Q3-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-08,Q3-2025,2025,TRANSPORT,ExternalCost,2200000,2156000 -2025-08,Q3-2025,2025,TRANSPORT,InternalCost,2640000, -2025-08,Q3-2025,2025,TRANSPORT,Premium,22000000,21560000 -2025-09,Q3-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-09,Q3-2025,2025,COMM_FIRE,Claims,30760000,31067600 -2025-09,Q3-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-09,Q3-2025,2025,COMM_FIRE,ExternalCost,4500000,4545000 -2025-09,Q3-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-09,Q3-2025,2025,COMM_FIRE,Premium,45000000,45450000 -2025-09,Q3-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-09,Q3-2025,2025,HOUSEHOLD,Claims,56568065,57133746 -2025-09,Q3-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-09,Q3-2025,2025,HOUSEHOLD,ExternalCost,7500000,7575000 -2025-09,Q3-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-09,Q3-2025,2025,HOUSEHOLD,Premium,78750000,79537500 -2025-09,Q3-2025,2025,LIABILITY,CapitalCost,2090000, -2025-09,Q3-2025,2025,LIABILITY,Claims,23940000,24179400 -2025-09,Q3-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-09,Q3-2025,2025,LIABILITY,ExternalCost,3800000,3838000 -2025-09,Q3-2025,2025,LIABILITY,InternalCost,4560000, -2025-09,Q3-2025,2025,LIABILITY,Premium,38000000,38380000 -2025-09,Q3-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-09,Q3-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28118400 -2025-09,Q3-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-09,Q3-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4848000 -2025-09,Q3-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-09,Q3-2025,2025,LIFE_HEALTH_EU,Premium,48000000,48480000 -2025-09,Q3-2025,2025,MOTOR,CapitalCost,3025000, -2025-09,Q3-2025,2025,MOTOR,Claims,40577778,40983556 -2025-09,Q3-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-09,Q3-2025,2025,MOTOR,ExternalCost,5500000,5555000 -2025-09,Q3-2025,2025,MOTOR,InternalCost,6600000, -2025-09,Q3-2025,2025,MOTOR,Premium,55000000,55550000 -2025-09,Q3-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-09,Q3-2025,2025,SPECIALTY_AVTN,Claims,15750000,15907500 -2025-09,Q3-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-09,Q3-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2525000 -2025-09,Q3-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-09,Q3-2025,2025,SPECIALTY_AVTN,Premium,25000000,25250000 -2025-09,Q3-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-09,Q3-2025,2025,TECH_RISK,Claims,15273244,15425976 -2025-09,Q3-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-09,Q3-2025,2025,TECH_RISK,ExternalCost,3200000,3232000 -2025-09,Q3-2025,2025,TECH_RISK,InternalCost,3840000, -2025-09,Q3-2025,2025,TECH_RISK,Premium,32000000,32320000 -2025-09,Q3-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-09,Q3-2025,2025,TRANSPORT,Claims,14774222,14921964 -2025-09,Q3-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-09,Q3-2025,2025,TRANSPORT,ExternalCost,2200000,2222000 -2025-09,Q3-2025,2025,TRANSPORT,InternalCost,2640000, -2025-09,Q3-2025,2025,TRANSPORT,Premium,22000000,22220000 -2025-10,Q4-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-10,Q4-2025,2025,COMM_FIRE,Claims,27250000,26432500 -2025-10,Q4-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-10,Q4-2025,2025,COMM_FIRE,ExternalCost,4500000,4365000 -2025-10,Q4-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-10,Q4-2025,2025,COMM_FIRE,Premium,45000000,43650000 -2025-10,Q4-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-10,Q4-2025,2025,HOUSEHOLD,Claims,52717205,51135689 -2025-10,Q4-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-10,Q4-2025,2025,HOUSEHOLD,ExternalCost,7500000,7275000 -2025-10,Q4-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-10,Q4-2025,2025,HOUSEHOLD,Premium,75000000,72750000 -2025-10,Q4-2025,2025,LIABILITY,CapitalCost,2090000, -2025-10,Q4-2025,2025,LIABILITY,Claims,23940000,23221800 -2025-10,Q4-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-10,Q4-2025,2025,LIABILITY,ExternalCost,3800000,3686000 -2025-10,Q4-2025,2025,LIABILITY,InternalCost,4560000, -2025-10,Q4-2025,2025,LIABILITY,Premium,38000000,36860000 -2025-10,Q4-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-10,Q4-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27004800 -2025-10,Q4-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-10,Q4-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4656000 -2025-10,Q4-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-10,Q4-2025,2025,LIFE_HEALTH_EU,Premium,48000000,46560000 -2025-10,Q4-2025,2025,MOTOR,CapitalCost,3025000, -2025-10,Q4-2025,2025,MOTOR,Claims,39081778,37909325 -2025-10,Q4-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-10,Q4-2025,2025,MOTOR,ExternalCost,5500000,5335000 -2025-10,Q4-2025,2025,MOTOR,InternalCost,6600000, -2025-10,Q4-2025,2025,MOTOR,Premium,55000000,53350000 -2025-10,Q4-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-10,Q4-2025,2025,SPECIALTY_AVTN,Claims,15750000,15277500 -2025-10,Q4-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-10,Q4-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2425000 -2025-10,Q4-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-10,Q4-2025,2025,SPECIALTY_AVTN,Premium,25000000,24250000 -2025-10,Q4-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-10,Q4-2025,2025,TECH_RISK,Claims,16860444,16354631 -2025-10,Q4-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-10,Q4-2025,2025,TECH_RISK,ExternalCost,3200000,3104000 -2025-10,Q4-2025,2025,TECH_RISK,InternalCost,3840000, -2025-10,Q4-2025,2025,TECH_RISK,Premium,32000000,31040000 -2025-10,Q4-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-10,Q4-2025,2025,TRANSPORT,Claims,15390222,14928515 -2025-10,Q4-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-10,Q4-2025,2025,TRANSPORT,ExternalCost,2200000,2134000 -2025-10,Q4-2025,2025,TRANSPORT,InternalCost,2640000, -2025-10,Q4-2025,2025,TRANSPORT,Premium,22000000,21340000 -2025-11,Q4-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-11,Q4-2025,2025,COMM_FIRE,Claims,26080000,26862400 -2025-11,Q4-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-11,Q4-2025,2025,COMM_FIRE,ExternalCost,4500000,4635000 -2025-11,Q4-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-11,Q4-2025,2025,COMM_FIRE,Premium,45000000,46350000 -2025-11,Q4-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-11,Q4-2025,2025,HOUSEHOLD,Claims,47246345,48663735 -2025-11,Q4-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-11,Q4-2025,2025,HOUSEHOLD,ExternalCost,7500000,7725000 -2025-11,Q4-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-11,Q4-2025,2025,HOUSEHOLD,Premium,71250000,73387500 -2025-11,Q4-2025,2025,LIABILITY,CapitalCost,2090000, -2025-11,Q4-2025,2025,LIABILITY,Claims,23940000,24658200 -2025-11,Q4-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-11,Q4-2025,2025,LIABILITY,ExternalCost,3800000,3914000 -2025-11,Q4-2025,2025,LIABILITY,InternalCost,4560000, -2025-11,Q4-2025,2025,LIABILITY,Premium,38000000,39140000 -2025-11,Q4-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-11,Q4-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28675200 -2025-11,Q4-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-11,Q4-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4944000 -2025-11,Q4-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-11,Q4-2025,2025,LIFE_HEALTH_EU,Premium,48000000,49440000 -2025-11,Q4-2025,2025,MOTOR,CapitalCost,3025000, -2025-11,Q4-2025,2025,MOTOR,Claims,37585778,38713351 -2025-11,Q4-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-11,Q4-2025,2025,MOTOR,ExternalCost,5500000,5665000 -2025-11,Q4-2025,2025,MOTOR,InternalCost,6600000, -2025-11,Q4-2025,2025,MOTOR,Premium,55000000,56650000 -2025-11,Q4-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-11,Q4-2025,2025,SPECIALTY_AVTN,Claims,15750000,16222500 -2025-11,Q4-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-11,Q4-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2575000 -2025-11,Q4-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-11,Q4-2025,2025,SPECIALTY_AVTN,Premium,25000000,25750000 -2025-11,Q4-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-11,Q4-2025,2025,TECH_RISK,Claims,17654044,18183665 -2025-11,Q4-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-11,Q4-2025,2025,TECH_RISK,ExternalCost,3200000,3296000 -2025-11,Q4-2025,2025,TECH_RISK,InternalCost,3840000, -2025-11,Q4-2025,2025,TECH_RISK,Premium,32000000,32960000 -2025-11,Q4-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-11,Q4-2025,2025,TRANSPORT,Claims,16006222,16486409 -2025-11,Q4-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-11,Q4-2025,2025,TRANSPORT,ExternalCost,2200000,2266000 -2025-11,Q4-2025,2025,TRANSPORT,InternalCost,2640000, -2025-11,Q4-2025,2025,TRANSPORT,Premium,22000000,22660000 -2025-12,Q4-2025,2025,COMM_FIRE,CapitalCost,2475000, -2025-12,Q4-2025,2025,COMM_FIRE,Claims,28420000,28420000 -2025-12,Q4-2025,2025,COMM_FIRE,ExpectedProfit,2250000, -2025-12,Q4-2025,2025,COMM_FIRE,ExternalCost,4500000,4500000 -2025-12,Q4-2025,2025,COMM_FIRE,InternalCost,5400000, -2025-12,Q4-2025,2025,COMM_FIRE,Premium,45000000,45000000 -2025-12,Q4-2025,2025,HOUSEHOLD,CapitalCost,4125000, -2025-12,Q4-2025,2025,HOUSEHOLD,Claims,48255484,48255484 -2025-12,Q4-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, -2025-12,Q4-2025,2025,HOUSEHOLD,ExternalCost,7500000,7500000 -2025-12,Q4-2025,2025,HOUSEHOLD,InternalCost,9000000, -2025-12,Q4-2025,2025,HOUSEHOLD,Premium,67500000,67500000 -2025-12,Q4-2025,2025,LIABILITY,CapitalCost,2090000, -2025-12,Q4-2025,2025,LIABILITY,Claims,23940000,23940000 -2025-12,Q4-2025,2025,LIABILITY,ExpectedProfit,1900000, -2025-12,Q4-2025,2025,LIABILITY,ExternalCost,3800000,3800000 -2025-12,Q4-2025,2025,LIABILITY,InternalCost,4560000, -2025-12,Q4-2025,2025,LIABILITY,Premium,38000000,38000000 -2025-12,Q4-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, -2025-12,Q4-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27840000 -2025-12,Q4-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2025-12,Q4-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4800000 -2025-12,Q4-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, -2025-12,Q4-2025,2025,LIFE_HEALTH_EU,Premium,48000000,48000000 -2025-12,Q4-2025,2025,MOTOR,CapitalCost,3025000, -2025-12,Q4-2025,2025,MOTOR,Claims,36089778,36089778 -2025-12,Q4-2025,2025,MOTOR,ExpectedProfit,2750000, -2025-12,Q4-2025,2025,MOTOR,ExternalCost,5500000,5500000 -2025-12,Q4-2025,2025,MOTOR,InternalCost,6600000, -2025-12,Q4-2025,2025,MOTOR,Premium,55000000,55000000 -2025-12,Q4-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, -2025-12,Q4-2025,2025,SPECIALTY_AVTN,Claims,15750000,15750000 -2025-12,Q4-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, -2025-12,Q4-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2500000 -2025-12,Q4-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, -2025-12,Q4-2025,2025,SPECIALTY_AVTN,Premium,25000000,25000000 -2025-12,Q4-2025,2025,TECH_RISK,CapitalCost,1760000, -2025-12,Q4-2025,2025,TECH_RISK,Claims,20034844,20034844 -2025-12,Q4-2025,2025,TECH_RISK,ExpectedProfit,1600000, -2025-12,Q4-2025,2025,TECH_RISK,ExternalCost,3200000,3200000 -2025-12,Q4-2025,2025,TECH_RISK,InternalCost,3840000, -2025-12,Q4-2025,2025,TECH_RISK,Premium,32000000,32000000 -2025-12,Q4-2025,2025,TRANSPORT,CapitalCost,1210000, -2025-12,Q4-2025,2025,TRANSPORT,Claims,16622222,16622222 -2025-12,Q4-2025,2025,TRANSPORT,ExpectedProfit,1100000, -2025-12,Q4-2025,2025,TRANSPORT,ExternalCost,2200000,2200000 -2025-12,Q4-2025,2025,TRANSPORT,InternalCost,2640000, -2025-12,Q4-2025,2025,TRANSPORT,Premium,22000000,22000000 -2026-01,Q1-2026,2026,COMM_FIRE,CapitalCost,2475000, -2026-01,Q1-2026,2026,COMM_FIRE,Claims,28420000,27283200 -2026-01,Q1-2026,2026,COMM_FIRE,ExpectedProfit,2250000, -2026-01,Q1-2026,2026,COMM_FIRE,ExternalCost,4500000,4320000 -2026-01,Q1-2026,2026,COMM_FIRE,InternalCost,5400000, -2026-01,Q1-2026,2026,COMM_FIRE,Premium,45000000,43200000 -2026-01,Q1-2026,2026,HOUSEHOLD,CapitalCost,4125000, -2026-01,Q1-2026,2026,HOUSEHOLD,Claims,48866345,46911691 -2026-01,Q1-2026,2026,HOUSEHOLD,ExpectedProfit,3750000, -2026-01,Q1-2026,2026,HOUSEHOLD,ExternalCost,7500000,7200000 -2026-01,Q1-2026,2026,HOUSEHOLD,InternalCost,9000000, -2026-01,Q1-2026,2026,HOUSEHOLD,Premium,71250000,68400000 -2026-01,Q1-2026,2026,LIABILITY,CapitalCost,2090000, -2026-01,Q1-2026,2026,LIABILITY,Claims,23940000,22982400 -2026-01,Q1-2026,2026,LIABILITY,ExpectedProfit,1900000, -2026-01,Q1-2026,2026,LIABILITY,ExternalCost,3800000,3648000 -2026-01,Q1-2026,2026,LIABILITY,InternalCost,4560000, -2026-01,Q1-2026,2026,LIABILITY,Premium,38000000,36480000 -2026-01,Q1-2026,2026,LIFE_HEALTH_EU,CapitalCost,2640000, -2026-01,Q1-2026,2026,LIFE_HEALTH_EU,Claims,27840000,26726400 -2026-01,Q1-2026,2026,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2026-01,Q1-2026,2026,LIFE_HEALTH_EU,ExternalCost,4800000,4608000 -2026-01,Q1-2026,2026,LIFE_HEALTH_EU,InternalCost,5760000, -2026-01,Q1-2026,2026,LIFE_HEALTH_EU,Premium,48000000,46080000 -2026-01,Q1-2026,2026,MOTOR,CapitalCost,3025000, -2026-01,Q1-2026,2026,MOTOR,Claims,36089778,34646187 -2026-01,Q1-2026,2026,MOTOR,ExpectedProfit,2750000, -2026-01,Q1-2026,2026,MOTOR,ExternalCost,5500000,5280000 -2026-01,Q1-2026,2026,MOTOR,InternalCost,6600000, -2026-01,Q1-2026,2026,MOTOR,Premium,55000000,52800000 -2026-01,Q1-2026,2026,SPECIALTY_AVTN,CapitalCost,1375000, -2026-01,Q1-2026,2026,SPECIALTY_AVTN,Claims,15750000,15120000 -2026-01,Q1-2026,2026,SPECIALTY_AVTN,ExpectedProfit,1250000, -2026-01,Q1-2026,2026,SPECIALTY_AVTN,ExternalCost,2500000,2400000 -2026-01,Q1-2026,2026,SPECIALTY_AVTN,InternalCost,3000000, -2026-01,Q1-2026,2026,SPECIALTY_AVTN,Premium,25000000,24000000 -2026-01,Q1-2026,2026,TECH_RISK,CapitalCost,1760000, -2026-01,Q1-2026,2026,TECH_RISK,Claims,18447644,17709738 -2026-01,Q1-2026,2026,TECH_RISK,ExpectedProfit,1600000, -2026-01,Q1-2026,2026,TECH_RISK,ExternalCost,3200000,3072000 -2026-01,Q1-2026,2026,TECH_RISK,InternalCost,3840000, -2026-01,Q1-2026,2026,TECH_RISK,Premium,32000000,30720000 -2026-01,Q1-2026,2026,TRANSPORT,CapitalCost,1210000, -2026-01,Q1-2026,2026,TRANSPORT,Claims,15390222,14774613 -2026-01,Q1-2026,2026,TRANSPORT,ExpectedProfit,1100000, -2026-01,Q1-2026,2026,TRANSPORT,ExternalCost,2200000,2112000 -2026-01,Q1-2026,2026,TRANSPORT,InternalCost,2640000, -2026-01,Q1-2026,2026,TRANSPORT,Premium,22000000,21120000 -2026-02,Q1-2026,2026,COMM_FIRE,CapitalCost,2475000, -2026-02,Q1-2026,2026,COMM_FIRE,Claims,27250000,27795000 -2026-02,Q1-2026,2026,COMM_FIRE,ExpectedProfit,2250000, -2026-02,Q1-2026,2026,COMM_FIRE,ExternalCost,4500000,4590000 -2026-02,Q1-2026,2026,COMM_FIRE,InternalCost,5400000, -2026-02,Q1-2026,2026,COMM_FIRE,Premium,45000000,45900000 -2026-02,Q1-2026,2026,HOUSEHOLD,CapitalCost,4125000, -2026-02,Q1-2026,2026,HOUSEHOLD,Claims,46879829,47817426 -2026-02,Q1-2026,2026,HOUSEHOLD,ExpectedProfit,3750000, -2026-02,Q1-2026,2026,HOUSEHOLD,ExternalCost,7500000,7650000 -2026-02,Q1-2026,2026,HOUSEHOLD,InternalCost,9000000, -2026-02,Q1-2026,2026,HOUSEHOLD,Premium,69000000,70380000 -2026-02,Q1-2026,2026,LIABILITY,CapitalCost,2090000, -2026-02,Q1-2026,2026,LIABILITY,Claims,23940000,24418800 -2026-02,Q1-2026,2026,LIABILITY,ExpectedProfit,1900000, -2026-02,Q1-2026,2026,LIABILITY,ExternalCost,3800000,3876000 -2026-02,Q1-2026,2026,LIABILITY,InternalCost,4560000, -2026-02,Q1-2026,2026,LIABILITY,Premium,38000000,38760000 -2026-02,Q1-2026,2026,LIFE_HEALTH_EU,CapitalCost,2640000, -2026-02,Q1-2026,2026,LIFE_HEALTH_EU,Claims,27840000,28396800 -2026-02,Q1-2026,2026,LIFE_HEALTH_EU,ExpectedProfit,2400000, -2026-02,Q1-2026,2026,LIFE_HEALTH_EU,ExternalCost,4800000,4896000 -2026-02,Q1-2026,2026,LIFE_HEALTH_EU,InternalCost,5760000, -2026-02,Q1-2026,2026,LIFE_HEALTH_EU,Premium,48000000,48960000 -2026-02,Q1-2026,2026,MOTOR,CapitalCost,3025000, -2026-02,Q1-2026,2026,MOTOR,Claims,34593778,35285654 -2026-02,Q1-2026,2026,MOTOR,ExpectedProfit,2750000, -2026-02,Q1-2026,2026,MOTOR,ExternalCost,5500000,5610000 -2026-02,Q1-2026,2026,MOTOR,InternalCost,6600000, -2026-02,Q1-2026,2026,MOTOR,Premium,55000000,56100000 -2026-02,Q1-2026,2026,SPECIALTY_AVTN,CapitalCost,1375000, -2026-02,Q1-2026,2026,SPECIALTY_AVTN,Claims,15750000,16065000 -2026-02,Q1-2026,2026,SPECIALTY_AVTN,ExpectedProfit,1250000, -2026-02,Q1-2026,2026,SPECIALTY_AVTN,ExternalCost,2500000,2550000 -2026-02,Q1-2026,2026,SPECIALTY_AVTN,InternalCost,3000000, -2026-02,Q1-2026,2026,SPECIALTY_AVTN,Premium,25000000,25500000 -2026-02,Q1-2026,2026,TECH_RISK,CapitalCost,1760000, -2026-02,Q1-2026,2026,TECH_RISK,Claims,16860444,17197653 -2026-02,Q1-2026,2026,TECH_RISK,ExpectedProfit,1600000, -2026-02,Q1-2026,2026,TECH_RISK,ExternalCost,3200000,3264000 -2026-02,Q1-2026,2026,TECH_RISK,InternalCost,3840000, -2026-02,Q1-2026,2026,TECH_RISK,Premium,32000000,32640000 -2026-02,Q1-2026,2026,TRANSPORT,CapitalCost,1210000, -2026-02,Q1-2026,2026,TRANSPORT,Claims,14774222,15069706 -2026-02,Q1-2026,2026,TRANSPORT,ExpectedProfit,1100000, -2026-02,Q1-2026,2026,TRANSPORT,ExternalCost,2200000,2244000 -2026-02,Q1-2026,2026,TRANSPORT,InternalCost,2640000, -2026-02,Q1-2026,2026,TRANSPORT,Premium,22000000,22440000 diff --git a/src/MeshWeaver.Blazor/Infrastructure/UserContextMiddleware.cs b/src/MeshWeaver.Blazor/Infrastructure/UserContextMiddleware.cs index fd4d31cc7..51ef04f04 100644 --- a/src/MeshWeaver.Blazor/Infrastructure/UserContextMiddleware.cs +++ b/src/MeshWeaver.Blazor/Infrastructure/UserContextMiddleware.cs @@ -11,8 +11,22 @@ namespace MeshWeaver.Blazor.Infrastructure; public class UserContextMiddleware(RequestDelegate next, ILogger logger) { + // Blazor framework files, static assets, and favicon — no user context needed. + private static readonly string[] ExcludedPrefixes = + ["/_framework", "/_content", "/_blazor", "/static/", "/favicon.ico"]; + public async Task InvokeAsync(HttpContext context) { + // Skip user resolution for static assets and Blazor framework resources. + // These requests never need an AccessContext and resolving it adds unnecessary + // overhead (hub lookup, mesh query) on every JS/CSS/SignalR resource download. + var path = context.Request.Path.Value ?? ""; + if (ExcludedPrefixes.Any(p => path.StartsWith(p, StringComparison.OrdinalIgnoreCase))) + { + await next(context); + return; + } + var hub = context.RequestServices.GetRequiredService().Hub; var userService = hub.ServiceProvider.GetRequiredService(); diff --git a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md index fee8a43bf..efe0a5b05 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md @@ -41,7 +41,7 @@ The `aspire deploy` command builds the application, pushes container images, and For local development with Docker containers: ```bash -aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj +aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode local ``` This starts in `local` mode by default, using Docker pgvector and emulated Azure services. @@ -99,6 +99,19 @@ Orleans provides distributed actor clustering for the microservices deployment. Telemetry and distributed tracing via Azure Application Insights, provisioned automatically in all deployed modes. +# Azure AD App Registration + +Microsoft authentication requires an app registration in Microsoft Entra ID (Azure AD): + +1. **Azure Portal** → **App registrations** → select your app (or create one) +2. Under **Authentication** → **Platform configurations** → **Web**, add redirect URIs: + - `http://localhost:5000/signin-microsoft` (local development) + - `https:///signin-microsoft` (deployed environments) +3. Note the **Application (client) ID** and **Directory (tenant) ID** from the **Overview** page +4. Under **Certificates & secrets**, create a client secret + +For single-tenant apps, the tenant ID must be configured — the default `/common` endpoint is not supported. + # Secrets Management Secrets are managed via `dotnet user-secrets` locally and GitHub secrets in CI/CD. @@ -113,6 +126,7 @@ Required secrets for distributed modes: | `Parameters:embedding-model` | Embedding model name | | `Parameters:microsoft-client-id` | Microsoft OAuth client ID | | `Parameters:microsoft-client-secret` | Microsoft OAuth client secret | +| `Parameters:microsoft-tenant-id` | Microsoft Entra tenant ID (single-tenant apps) | | `Parameters:google-client-id` | Google OAuth client ID | | `Parameters:google-client-secret` | Google OAuth client secret | | `Parameters:custom-domain` | Custom domain for deployed portal | diff --git a/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md b/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md index f57d5aee9..027836c03 100644 --- a/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md +++ b/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md @@ -12,6 +12,8 @@ This guide explains how to configure data in message hubs, including data source MeshWeaver provides flexible data configuration patterns: - **AddSource**: Configure local data sources with optional initialization - **AddHubSource**: Synchronize data from parent or related hubs +- **AddPartitionedHubSource**: Aggregate data from multiple child hubs by partition +- **WithVirtualDataSource**: Load data from reactive streams (mesh queries, node content, etc.) - **WithInitialData**: Seed data sources with predefined records # Data Model Relationships @@ -208,3 +210,91 @@ When a `DataChangeRequest` arrives at the Todo hub, changes are persisted to sto ``` This configuration enables the Todo hub to access Status reference data from its parent Project hub, ensuring consistent status options across the hierarchy. + +# Partitioned Hub Data Source + +## AddPartitionedHubSource + +Use `AddPartitionedHubSource` to aggregate data from multiple child hubs into a parent hub. Each child hub owns its own data; the parent reads from them as live streams. This is the data mesh pattern for cross-domain data composition. + +### When to Use + +- A group/parent hub needs to consolidate data from multiple domain hubs +- Each domain hub independently owns and manages its data +- The consolidated view should update reactively when any domain's data changes + +### Configuration Example + +```csharp +config => config + .AddData(data => data + .AddPartitionedHubSource
( + c => c.WithType( + row => (Address)("Namespace/" + row.Partition + "/Analysis")) + .InitializingPartitions( + (Address)"Namespace/PartitionA/Analysis", + (Address)"Namespace/PartitionB/Analysis"))) +``` + +The `WithType` lambda maps each data row to the hub address that owns it. `InitializingPartitions` lists the addresses to subscribe to on startup. + +### Data Flow + +```mermaid +graph LR + A[Hub A
owns data] -->|stream| P[Parent Hub
PartitionedHubDataSource] + B[Hub B
owns data] -->|stream| P + C[Hub C
owns data] -->|stream| P + P --> V[Consolidated View] + + classDef domain fill:#e8f0fe,stroke:#4285f4,color:#333 + classDef parent fill:#e6f4ea,stroke:#34a853,color:#333 + class A,B,C domain + class P,V parent +``` + +Adding a new partition is a single address — no new ETL pipeline, no data copying. + +# Virtual Data Sources + +## WithVirtualDataSource + +Use `WithVirtualDataSource` to load data from reactive `IObservable` streams — e.g., mesh node queries, computed data, or embedded node content. + +### Loading from Mesh Node Queries + +```csharp +config => config + .AddData(data => data + .WithVirtualDataSource("ReferenceData", vs => vs + .WithVirtualType(workspace => + { + var meshQuery = workspace.Hub.ServiceProvider + .GetRequiredService(); + return meshQuery.ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:ExchangeRate")); + }))) +``` + +### Loading from Embedded Node Content + +When data is stored as structured arrays inside a MeshNode's `Content` field, load it by querying the node and extracting the embedded data: + +```csharp +config => config + .WithContentType() + .AddData(data => data + .WithVirtualDataSource("LocalData", vs => vs + .WithVirtualType(workspace => + LoadDataFromContent(workspace)))) +``` + +This pattern is deployment-mode independent — the same code works whether the MeshNode is stored on the filesystem, in PostgreSQL, or in Cosmos DB. + +### When to Use Which Pattern + +| Pattern | Use When | +|---------|----------| +| **Individual MeshNodes** | Each row is an independently editable entity (users, products, orders) | +| **Embedded content array** | Data is loaded as a unit, read-heavy, updated as a batch (datacubes, time series) | +| **External files (CSV, etc.)** | Legacy integration only — not recommended for new development (filesystem-dependent) | diff --git a/src/MeshWeaver.Hosting.Blazor/BlazorHostingExtensions.cs b/src/MeshWeaver.Hosting.Blazor/BlazorHostingExtensions.cs index 47c314b26..17a0c2b5b 100644 --- a/src/MeshWeaver.Hosting.Blazor/BlazorHostingExtensions.cs +++ b/src/MeshWeaver.Hosting.Blazor/BlazorHostingExtensions.cs @@ -37,7 +37,6 @@ public static MeshBuilder AddBlazor(this MeshBuilder builder, Func(); // Thumbnail preview stub (returns 501 until implemented) app.MapGet("/layout-preview/{area}", (string area) => Results.StatusCode(StatusCodes.Status501NotImplemented)); diff --git a/test/MeshWeaver.AI.Test/SchemaValidationTest.cs b/test/MeshWeaver.AI.Test/SchemaValidationTest.cs index e819d9cae..1bb7a801f 100644 --- a/test/MeshWeaver.AI.Test/SchemaValidationTest.cs +++ b/test/MeshWeaver.AI.Test/SchemaValidationTest.cs @@ -175,9 +175,10 @@ public async Task Create_WithSlashInId_SanitizesAndCreates() { var plugin = CreatePlugin(); + var uniqueSuffix = Guid.NewGuid().ToString("N")[..8]; var nodeJson = JsonSerializer.Serialize(new { - id = "ACME/Product/PricingTool", + id = $"ACME/Product/PricingTool-{uniqueSuffix}", @namespace = "", name = "Pricing Tool", nodeType = "Markdown" diff --git a/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs b/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs index 4fce466fd..8b411af77 100644 --- a/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs +++ b/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs @@ -701,7 +701,9 @@ await meshQuery Output.WriteLine("Node confirmed as Active."); // Step 5: Use GetDataRequest to retrieve the MeshNode via EntityReference - var entityRef = new EntityReference(nameof(MeshNode), nodePath); + // MeshNode key is Id (last segment), not full path + var nodeId = nodePath[(nodePath.LastIndexOf('/') + 1)..]; + var entityRef = new EntityReference(nameof(MeshNode), nodeId); var getDataResponse = await client.AwaitResponse( new GetDataRequest(entityRef), o => o.WithTarget(nodeAddress), diff --git a/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs b/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs index 8f382c2e3..e1b2ea6ca 100644 --- a/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs +++ b/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs @@ -44,6 +44,8 @@ protected override MeshBuilder ConfigureMesh(MeshBuilder builder) { var graphPath = TestPaths.SamplesGraph; var dataDirectory = TestPaths.SamplesGraphData; + if (Directory.Exists(SharedCacheDirectory)) + Directory.Delete(SharedCacheDirectory, recursive: true); Directory.CreateDirectory(SharedCacheDirectory); var configuration = new ConfigurationBuilder() @@ -1166,7 +1168,7 @@ public async Task Group_HubInitialization_ShouldSucceedWithoutPreInit() /// Pre-initializes child BU analysis hubs (EuropeRe, AmericasIns) so their data /// is loaded before the group hub's PartitionedHubDataSource tries to aggregate. /// Without this, the remote streams may receive empty data if child hubs haven't - /// finished loading their CSV data when the group hub subscribes. + /// finished loading their datacube from node content when the group hub subscribes. ///
private async Task InitializeChildAnalysisHubs() { diff --git a/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj b/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj index 89afe9101..ccce9f9c0 100644 --- a/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj +++ b/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj @@ -23,6 +23,7 @@ + From 1948b7aa89be3dfe2e98fd0967298d61114e2626 Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Fri, 10 Apr 2026 17:26:48 +0200 Subject: [PATCH 06/14] aspire-deployment-changes --- memex/Memex.Portal.Monolith/Program.cs | 14 +++ .../Memex.Portal.Shared/MemexConfiguration.cs | 11 ++ memex/aspire/Memex.AppHost/Program.cs | 35 ++++-- .../Memex.Database.Migration/Program.cs | 100 ++++++++++++++++++ 4 files changed, 149 insertions(+), 11 deletions(-) diff --git a/memex/Memex.Portal.Monolith/Program.cs b/memex/Memex.Portal.Monolith/Program.cs index 08c6a1ce2..9544b3e33 100644 --- a/memex/Memex.Portal.Monolith/Program.cs +++ b/memex/Memex.Portal.Monolith/Program.cs @@ -1,5 +1,6 @@ using Memex.Portal.ServiceDefaults; using Memex.Portal.Shared; +using MeshWeaver.AI; using MeshWeaver.ContentCollections; using MeshWeaver.Graph.Configuration; using MeshWeaver.Hosting; @@ -67,6 +68,19 @@ var app = builder.Build(); +// DIAGNOSTIC — remove after fix confirmed +try +{ + var factories = app.Services.GetServices().ToList(); + Console.WriteLine($"[DIAG] IChatClientFactory count from root DI: {factories.Count}"); + foreach (var f in factories) + Console.WriteLine($"[DIAG] {f.GetType().Name}: Name={f.Name}, Models=[{string.Join(", ", f.Models)}], Order={f.Order}"); +} +catch (Exception ex) +{ + Console.WriteLine($"[DIAG] IChatClientFactory resolution FAILED: {ex.GetType().Name}: {ex.Message}\n{ex}"); +} + // Map Aspire default endpoints (health checks) app.MapDefaultEndpoints(); diff --git a/memex/Memex.Portal.Shared/MemexConfiguration.cs b/memex/Memex.Portal.Shared/MemexConfiguration.cs index b22dfaeed..014f4d010 100644 --- a/memex/Memex.Portal.Shared/MemexConfiguration.cs +++ b/memex/Memex.Portal.Shared/MemexConfiguration.cs @@ -91,6 +91,17 @@ public static void ConfigureMemexServices(this WebApplicationBuilder builder) services.AddAzureFoundry(config => builder.Configuration.GetSection("AzureAIS").Bind(config)); + // DIAGNOSTIC — remove after fix confirmed + { + var probe = new MeshWeaver.AI.AzureFoundry.AzureFoundryConfiguration(); + builder.Configuration.GetSection("AzureAIS").Bind(probe); + Console.WriteLine( + $"[DIAG:AzureAIS] Endpoint={probe.Endpoint ?? "(null)"}, " + + $"ApiKey={(!string.IsNullOrEmpty(probe.ApiKey) ? "SET" : "MISSING")}, " + + $"Models.Length={probe.Models.Length}: [{string.Join(", ", probe.Models)}], " + + $"Order={probe.Order}"); + } + services.AddAzureOpenAI(config => builder.Configuration.GetSection("AzureOpenAIS").Bind(config)); diff --git a/memex/aspire/Memex.AppHost/Program.cs b/memex/aspire/Memex.AppHost/Program.cs index e031d64f3..fb49370a3 100644 --- a/memex/aspire/Memex.AppHost/Program.cs +++ b/memex/aspire/Memex.AppHost/Program.cs @@ -50,14 +50,22 @@ var microsoftClientSecret = builder.AddParameter("microsoft-client-secret", secret: true); var microsoftTenantId = builder.AddParameter("microsoft-tenant-id", secret: false); -// Embedding, Google auth, and custom domain -var embeddingEndpoint = builder.AddParameter("embedding-endpoint", secret: false); -var embeddingKey = builder.AddParameter("embedding-key", secret: true); -var embeddingModel = builder.AddParameter("embedding-model", secret: false); -var googleClientId = builder.AddParameter("google-client-id", secret: false); -var googleClientSecret = builder.AddParameter("google-client-secret", secret: true); -var customDomain = builder.AddParameter("custom-domain", secret: false); -var certificateName = builder.AddParameter("certificate-name", secret: false); +// Embedding, Google auth, and custom domain (non-secret optional — ACA accepts empty env vars) +var embeddingEndpoint = builder.AddParameter("embedding-endpoint", value: "", secret: false); +var embeddingModel = builder.AddParameter("embedding-model", value: "", secret: false); +var googleClientId = builder.AddParameter("google-client-id", value: "", secret: false); +var customDomain = builder.AddParameter("custom-domain", value: "", secret: false); +var certificateName = builder.AddParameter("certificate-name", value: "", secret: false); + +// Optional secrets/params: ACA rejects secrets with empty values; ConfigureCustomDomain +// rejects empty hostnames. Read actual config values to guard optional registrations. +var embeddingKeyValue = builder.Configuration["Parameters:embedding-key"] ?? ""; +var googleClientSecretValue = builder.Configuration["Parameters:google-client-secret"] ?? ""; +var customDomainValue = builder.Configuration["Parameters:custom-domain"] ?? ""; +IResourceBuilder? embeddingKey = string.IsNullOrEmpty(embeddingKeyValue) + ? null : builder.AddParameter("embedding-key", secret: true); +IResourceBuilder? googleClientSecret = string.IsNullOrEmpty(googleClientSecretValue) + ? null : builder.AddParameter("google-client-secret", secret: true); // --- Infrastructure axes --- var isDeployed = mode is "test" or "prod"; @@ -124,7 +132,6 @@ .WithEnvironment("ASPNETCORE_ENVIRONMENT", isDeployed ? "Production" : "Development") // Embedding .WithEnvironment("Embedding__Endpoint", embeddingEndpoint) - .WithEnvironment("Embedding__ApiKey", embeddingKey) .WithEnvironment("Embedding__Model", embeddingModel) // LLM: Anthropic (Azure Foundry Claude) .WithEnvironment("Anthropic__Endpoint", "https://s-meshweaver.services.ai.azure.com/anthropic/") @@ -155,7 +162,6 @@ .WithEnvironment("Authentication__Microsoft__ClientSecret", microsoftClientSecret) .WithEnvironment("Authentication__Microsoft__TenantId", microsoftTenantId) .WithEnvironment("Authentication__Google__ClientId", googleClientId) - .WithEnvironment("Authentication__Google__ClientSecret", googleClientSecret) // Wait for dependencies .WaitFor(orleansTables) .WaitForCompletion(dbMigration) @@ -163,7 +169,8 @@ .PublishAsAzureContainerApp((module, app) => { app.Configuration.Ingress.StickySessionsAffinity = StickySessionAffinity.Sticky; - app.ConfigureCustomDomain(customDomain, certificateName); + if (!string.IsNullOrEmpty(customDomainValue)) + app.ConfigureCustomDomain(customDomain, certificateName); // Scale: min 2 replicas (Orleans needs ≥2 for resilience), max 6 under load. // Each replica: 2 vCPU / 4Gi (50% of Consumption tier max 4 vCPU / 8Gi). @@ -171,6 +178,12 @@ app.Template.Scale.MaxReplicas = 6; }); +// Optional secrets: only add as env vars when configured (ACA rejects empty secrets) +if (embeddingKey is not null) + portal.WithEnvironment("Embedding__ApiKey", embeddingKey); +if (googleClientSecret is not null) + portal.WithEnvironment("Authentication__Google__ClientSecret", googleClientSecret); + // --- Azure Blob Storage --- if (useLocalDb) { diff --git a/memex/aspire/Memex.Database.Migration/Program.cs b/memex/aspire/Memex.Database.Migration/Program.cs index d578cf956..aa0fbe18e 100644 --- a/memex/aspire/Memex.Database.Migration/Program.cs +++ b/memex/aspire/Memex.Database.Migration/Program.cs @@ -428,6 +428,106 @@ EXCEPTION WHEN OTHERS THEN logger.LogInformation("Repair v5 completed."); } +// ── Data repair v6: Rebuild user_effective_permissions for all schemas ── +// Ensures self-assignments and permissions are correct after fresh deployments, +// schema re-initialization, or any silent failure in UserScopeGrantHandler. +// This runs on fresh DBs (currentVersion=5 is set, not 6) and existing DBs alike. +if (currentVersion < 6) +{ + logger.LogInformation("Running repair v6: Ensure user self-assignments and rebuild all permissions..."); + await using (var cmd = dataSource.CreateCommand(""" + DO $$ + DECLARE + user_rec RECORD; + schema_rec RECORD; + assignment_exists BOOLEAN; + user_schema_exists BOOLEAN; + BEGIN + -- Guard: user schema may not exist on fresh DBs + SELECT EXISTS( + SELECT 1 FROM information_schema.schemata + WHERE schema_name = 'user' + ) INTO user_schema_exists; + + IF user_schema_exists THEN + -- Ensure every User node has an Admin self-assignment + FOR user_rec IN + SELECT id FROM "user".mesh_nodes WHERE node_type = 'User' + LOOP + SELECT EXISTS( + SELECT 1 FROM "user".access + WHERE namespace = 'User/' || user_rec.id || '/_Access' + AND content->>'accessObject' = user_rec.id + ) INTO assignment_exists; + + IF NOT assignment_exists THEN + INSERT INTO "user".access (id, namespace, name, node_type, content, main_node, last_modified, version, state) + VALUES ( + user_rec.id || '_SelfAccess', + 'User/' || user_rec.id || '/_Access', + user_rec.id || ' Self Access', + 'AccessAssignment', + jsonb_build_object( + 'accessObject', user_rec.id, + 'displayName', user_rec.id, + 'roles', jsonb_build_array(jsonb_build_object('role', 'Admin')) + ), + 'User/' || user_rec.id, + NOW(), 1, 2 + ); + RAISE NOTICE 'v6: Created self-assignment for user %', user_rec.id; + END IF; + END LOOP; + + -- Rebuild permissions for user schema + BEGIN + PERFORM "user".rebuild_user_effective_permissions(); + RAISE NOTICE 'v6: Rebuilt permissions for user schema'; + EXCEPTION WHEN OTHERS THEN + RAISE NOTICE 'v6: user schema rebuild failed: %', SQLERRM; + END; + ELSE + RAISE NOTICE 'v6: user schema does not exist yet — skipping (trigger will handle first login)'; + END IF; + + -- Rebuild permissions for all other content schemas + FOR schema_rec IN + SELECT schema_name FROM information_schema.schemata s + WHERE EXISTS (SELECT 1 FROM information_schema.tables t + WHERE t.table_schema = s.schema_name AND t.table_name = 'access') + AND s.schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast', 'user') + AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' + LOOP + BEGIN + EXECUTE format('SELECT %I.rebuild_user_effective_permissions()', schema_rec.schema_name); + RAISE NOTICE 'v6: Rebuilt permissions for schema %', schema_rec.schema_name; + EXCEPTION WHEN OTHERS THEN + RAISE NOTICE 'v6: Schema % rebuild failed: %', schema_rec.schema_name, SQLERRM; + END; + END LOOP; + END $$; + """)) + { + await cmd.ExecuteNonQueryAsync(); + } + + currentVersion = 6; + logger.LogInformation("Repair v6 completed."); +} + +// ── Always: rebuild user_effective_permissions to catch any new logins since last deploy ── +try +{ + await using var rebuildCmd = dataSource.CreateCommand( + "SELECT \"user\".rebuild_user_effective_permissions()"); + await rebuildCmd.ExecuteNonQueryAsync(); + logger.LogInformation("Rebuilt user_effective_permissions for user schema."); +} +catch (Exception ex) +{ + logger.LogWarning(ex, "Could not rebuild user_effective_permissions (user schema may not exist yet)."); +} + // ── Always: populate searchable_schemas from remaining content partitions ── // This runs every time (not versioned) since it's idempotent and schemas may change. { From 214b4e80b75225337fb60c77b381c7dd833755ad Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Sun, 12 Apr 2026 15:26:05 +0200 Subject: [PATCH 07/14] strip non-deployment changes from branch Co-Authored-By: Claude Opus 4.6 --- .github/workflows/dotnet-test.yml | 6 +- .github/workflows/publish-github.yml | 4 +- .github/workflows/release-packages.yml | 4 +- .gitignore | 2 + CLAUDE.md | 4 + Directory.Packages.props | 31 +- .../templates/aspire/Memex.AppHost/Program.cs | 7 +- .../Authentication/ApiTokenService.cs | 22 +- .../OrganizationNodeType.cs | 13 +- .../appsettings.Development.json | 4 +- .../Memex.Portal.Distributed/appsettings.json | 4 +- .../Data/FutuRe/AmericasIns/Analysis.json | 7780 +---------------- .../LineOfBusiness/AGRICULTURE.json | 2 +- .../LineOfBusiness/COMMERCIAL.json | 2 +- .../LineOfBusiness/CYBER_TECH.json | 2 +- .../LineOfBusiness/ENERGY_MINING.json | 2 +- .../LineOfBusiness/HOMEOWNERS.json | 2 +- .../AmericasIns/LineOfBusiness/LIFE_ANN.json | 2 +- .../LineOfBusiness/SPECIALTY_AVTN_US.json | 2 +- .../LineOfBusiness/WORKERS_COMP.json | 2 +- .../_Source/ExternalDependencies.cs | 7 - .../AME-AGRICULTURE-AGRI.json | 2 +- .../AME-COMMERCIAL-CAS.json | 2 +- .../AME-COMMERCIAL-MARINE.json | 2 +- .../AME-COMMERCIAL-PROP.json | 2 +- .../AME-CYBER_TECH-CYBER.json | 2 +- .../AME-CYBER_TECH-PROF.json | 2 +- .../AME-ENERGY_MINING-ENRG.json | 2 +- .../AME-ENERGY_MINING-PROP.json | 2 +- .../AME-HOMEOWNERS-CAS.json | 2 +- .../AME-HOMEOWNERS-PROP.json | 2 +- .../TransactionMapping/AME-LIFE_ANN-LH.json | 2 +- .../AME-SPECIALTY_AVTN_US-AVTN.json | 2 +- .../AME-SPECIALTY_AVTN_US-SPEC.json | 2 +- .../AME-WORKERS_COMP-CAS.json | 2 +- .../Graph/Data/FutuRe/AsiaRe/Analysis.json | 7780 +---------------- .../_Source/ExternalDependencies.cs | 7 - samples/Graph/Data/FutuRe/DataDistribution.md | 40 +- .../Graph/Data/FutuRe/EuropeRe/Analysis.json | 7780 +---------------- .../EuropeRe/LineOfBusiness/COMM_FIRE.json | 2 +- .../EuropeRe/LineOfBusiness/HOUSEHOLD.json | 2 +- .../EuropeRe/LineOfBusiness/LIABILITY.json | 2 +- .../LineOfBusiness/LIFE_HEALTH_EU.json | 2 +- .../FutuRe/EuropeRe/LineOfBusiness/MOTOR.json | 2 +- .../LineOfBusiness/SPECIALTY_AVTN.json | 2 +- .../EuropeRe/LineOfBusiness/TECH_RISK.json | 2 +- .../EuropeRe/LineOfBusiness/TRANSPORT.json | 2 +- .../_Source/ExternalDependencies.cs | 7 - .../EUR-COMM_FIRE-ENRG.json | 2 +- .../EUR-COMM_FIRE-PROP.json | 2 +- .../TransactionMapping/EUR-HOUSEHOLD-CAS.json | 2 +- .../EUR-HOUSEHOLD-PROP.json | 2 +- .../TransactionMapping/EUR-LIABILITY-CAS.json | 2 +- .../EUR-LIABILITY-PROF.json | 2 +- .../EUR-LIFE_HEALTH_EU-LH.json | 2 +- .../TransactionMapping/EUR-MOTOR-CAS.json | 19 +- .../EUR-SPECIALTY_AVTN-AVTN.json | 2 +- .../EUR-SPECIALTY_AVTN-SPEC.json | 2 +- .../EUR-TECH_RISK-CYBER.json | 2 +- .../EUR-TECH_RISK-PROF.json | 2 +- .../EUR-TRANSPORT-MARINE.json | 2 +- .../GroupAnalysis/_Source/AnalysisContent.cs | 23 - .../GroupAnalysis/_Source/FutuReDataLoader.cs | 289 +- .../_Source/ProfitabilityLayoutAreas.cs | 2 +- .../_Source/LocalAnalysisConfig.cs | 15 +- .../_Source/TransactionMapping.cs | 4 +- samples/Graph/Data/FutuRe/WhyDataMesh.md | 2 +- samples/Graph/Data/FutuRe/index.md | 34 +- .../FutuRe/AmericasIns/Analysis/datacube.csv | 865 ++ .../FutuRe/AsiaRe/Analysis/datacube.csv | 865 ++ .../FutuRe/EuropeRe/Analysis/datacube.csv | 865 ++ .../AmericasIns/LineOfBusiness/icon.svg | 9 +- .../Graph/content/FutuRe/AmericasIns/icon.svg | 9 +- .../FutuRe/AsiaRe/LineOfBusiness/icon.svg | 9 +- samples/Graph/content/FutuRe/AsiaRe/icon.svg | 9 +- .../FutuRe/EuropeRe/LineOfBusiness/icon.svg | 9 +- .../Graph/content/FutuRe/EuropeRe/icon.svg | 9 +- .../content/FutuRe/LineOfBusiness/icon.svg | 9 +- .../AzureClaudeChatClient.cs | 52 +- src/MeshWeaver.AI/AIExtensions.cs | 8 +- src/MeshWeaver.AI/AgentChatClient.cs | 193 +- src/MeshWeaver.AI/ChatClientAgentFactory.cs | 271 +- src/MeshWeaver.AI/Data/Agent/Coder.md | 10 + .../Data/Agent/CommentingReference.md | 1 + src/MeshWeaver.AI/Data/Agent/Orchestrator.md | 24 +- .../Data/Agent/ToolsReference.md | 94 +- src/MeshWeaver.AI/Data/Agent/Worker.md | 31 +- src/MeshWeaver.AI/IAgentChat.cs | 15 + src/MeshWeaver.AI/InternalsVisibleTo.cs | 4 + src/MeshWeaver.AI/Layout/ThreadsLayoutArea.cs | 45 - src/MeshWeaver.AI/MeshOperations.cs | 51 +- src/MeshWeaver.AI/MeshPlugin.cs | 61 +- src/MeshWeaver.AI/SubmitMessageRequest.cs | 20 + src/MeshWeaver.AI/Thread.cs | 49 +- src/MeshWeaver.AI/ThreadExecution.cs | 879 +- src/MeshWeaver.AI/ThreadLayoutAreas.cs | 233 +- .../ThreadMessageActionRequests.cs | 39 +- src/MeshWeaver.AI/ThreadMessageHandlers.cs | 106 + src/MeshWeaver.AI/ThreadMessageLayoutAreas.cs | 215 +- src/MeshWeaver.AI/ThreadMessageViewModel.cs | 1 - src/MeshWeaver.AI/ThreadNodeType.cs | 53 +- src/MeshWeaver.AI/ThreadViewModel.cs | 6 +- .../Threading/MeshDataSourceThreadManager.cs | 1 - src/MeshWeaver.AI/ToolStatusFormatter.cs | 11 +- .../UpdateThreadMessageContent.cs | 2 +- .../Chat/ThreadChatView.razor | 40 +- .../Chat/ThreadChatView.razor.cs | 344 +- .../RadzenChartView.razor | 3 +- .../Components/LayoutAreaView.razor.cs | 7 +- .../Components/MarkdownView.razor.cs | 22 +- .../Components/MeshSearchView.razor | 28 +- .../Components/MeshSearchView.razor.cs | 32 +- .../Components/MeshSearchView.razor.css | 14 + .../Components/NamedAreaView.razor.cs | 1 - .../Components/ThreadMessageBubbleView.razor | 89 +- .../ThreadMessageBubbleView.razor.cs | 7 + .../FileExplorer/FileBrowser.razor.cs | 5 +- .../Pages/ContentPage.razor.cs | 16 +- .../AzureBlobStreamProvider.cs | 16 +- .../Completion/ContentAutocompleteProvider.cs | 192 +- .../ContentCollection.cs | 32 + .../ContentCollectionsExtensions.cs | 4 + .../ContentLayoutArea.cs | 37 + .../DocSharpContentTransformer.cs | 21 + .../FileContentProvider.cs | 24 +- .../IContentTransformer.cs | 18 + .../MeshWeaver.ContentCollections.csproj | 1 + src/MeshWeaver.Data.Contract/Messages.cs | 9 +- src/MeshWeaver.Data/DataContext.cs | 7 +- src/MeshWeaver.Data/DataExtensions.cs | 67 + .../JsonSynchronizationStream.cs | 14 +- .../Validation/RlsDataValidator.cs | 4 +- .../Data/AI/Tools/MeshPlugin.md | 1 + .../Data/Architecture/AccessControl.md | 48 + .../Data/Architecture/AsynchronousCalls.md | 180 + .../Data/Architecture/DataAccessPatterns.md | 1 + .../Architecture/SatelliteEntityPatterns.md | 1 + .../Architecture/SatelliteNodePatterns.md | 7 + .../Data/Architecture/WorkspaceReferences.md | 1 + .../Data/DataMesh/DataConfiguration.md | 90 - .../Data/DataMesh/NodeOperations.md | 1 + .../Data/GUI/DataBinding/ItemTemplate.md | 1 + .../Data/GUI/NodeMenu.md | 1 + .../Data/GUI/SidePanel.md | 1 + .../LoggingBuilderExtensions.cs | 6 +- .../Configuration/ApiTokenNodeType.cs | 78 +- .../Configuration/UserNodeType.cs | 35 +- src/MeshWeaver.Graph/MeshDataSource.cs | 6 +- src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs | 3 +- src/MeshWeaver.Graph/NodeTypeLayoutAreas.cs | 3 +- .../Security/RlsNodeValidator.cs | 11 +- .../UserActivityLayoutAreas.cs | 28 +- .../CircuitAccessHandler.cs | 19 +- .../AccessContextGrainCallFilter.cs | 32 +- .../MessageHubGrain.cs | 113 +- .../OrleansMeshChangeFeed.cs | 69 + .../OrleansServerRegistryExtensions.cs | 10 + .../PathCacheInvalidatorGrain.cs | 68 + .../RoutingGrain.cs | 39 +- .../PostgreSqlCrossSchemaQueryProvider.cs | 27 + .../PostgreSqlMeshQuery.cs | 4 + .../PostgreSqlSqlGenerator.cs | 46 +- src/MeshWeaver.Hosting/MeshCatalog.cs | 45 +- src/MeshWeaver.Hosting/MeshChangeFeed.cs | 54 + .../PathResolutionService.cs | 113 + .../Persistence/PersistenceExtensions.cs | 5 +- .../Persistence/PersistenceService.cs | 2 +- .../Query/RoutingMeshQueryProvider.cs | 25 +- .../SecurePersistenceServiceDecorator.cs | 2 +- .../Security/SecurityService.cs | 12 +- src/MeshWeaver.Layout/Catalog/CatalogTypes.cs | 7 + .../Client/LayoutClientExtensions.cs | 31 +- src/MeshWeaver.Layout/MeshSearchControl.cs | 3 + .../ThreadMessageActionRequests.cs | 25 + .../ThreadMessageBubbleControl.cs | 6 + .../CreateNodeRequest.cs | 1 + .../MeshExtensions.cs | 43 +- .../Query/QueryParser.cs | 13 +- .../Security/UserAccess.cs | 7 + .../Services/ICrossSchemaQueryProvider.cs | 12 + .../Services/IMeshChangeFeed.cs | 64 + .../Services/IMeshQueryCore.cs | 12 +- .../HeartBeatEvent.cs | 23 + .../IMessageDelivery.cs | 2 + .../MessageHubExtensions.cs | 27 + .../ReadOnlyCollectionConverterFactory.cs | 31 +- .../SchemaValidationTest.cs | 3 +- .../ThreadAgentIntegrationTest.cs | 2 - .../TodoCreateFlowTest.cs | 4 +- .../ContentReferenceIntegrityTest.cs | 4 + .../DocxConversionTest.cs | 235 + .../MeshWeaver.ContentCollections.Test.csproj | 1 + .../FutuReAnalysisTest.cs | 267 +- .../FxConversionTest.cs | 14 +- .../MeshWeaver.FutuRe.Test.csproj | 1 - .../MeshChangeFeedTest.cs | 137 + .../DelegationCompletionTest.cs | 166 + .../MeshWeaver.Hosting.Orleans.Test.csproj | 3 + .../OrleansApiTokenTest.cs | 99 + .../OrleansAutoExecuteTest.cs | 205 + .../OrleansChatHistoryTest.cs | 143 + .../OrleansDelegationFlowTest.cs | 326 + .../OrleansDelegationStartTest.cs | 191 + .../OrleansDelegationTest.cs | 423 + .../OrleansMeshChangeFeedTest.cs | 172 + .../OrleansNodeChangePropagationTest.cs | 592 ++ .../OrleansPortalFlowTest.cs | 283 + .../OrleansReentrancyTest.cs | 296 + .../OrleansSubThreadRoutingTest.cs | 307 + .../OrleansTestMeshExtensions.cs | 5 - .../OrleansThreadAccessTest.cs | 1 - .../OrleansThreadStreamingTest.cs | 61 +- .../SharedOrleansFixture.cs | 228 + .../appsettings.json | 10 + .../xunit.runner.json | 6 + .../CrossPartitionSearchTests.cs | 43 +- .../FirstUserOnboardingTests.cs | 9 +- .../GlobalAdminOrganizationSearchTests.cs | 36 +- .../ThreadMessageChatTests.cs | 28 +- .../ThreadPathResolutionTest.cs | 237 + .../UserActivityCrossPartitionTests.cs | 60 + .../ApiTokenAccessTest.cs | 104 + .../MeshPluginAccessContextTest.cs | 126 + .../xunit.runner.json | 2 +- .../AddressResolutionTest.cs | 2 - .../ThreadAccessTest.cs | 2 - .../ThreadStreamingIdentityTest.cs | 1 + .../UserPublicReadTest.cs | 19 +- .../AccessContextToolCallTest.cs | 137 + .../AutoExecuteFlowTest.cs | 233 + .../BinaryAttachmentTest.cs | 142 + .../CancelThreadExecutionTest.cs | 17 +- .../ChatHistoryTest.cs | 201 + .../DelegationExecutionTest.cs | 42 +- .../DelegationFailureTest.cs | 190 + .../DelegationSubThreadTest.cs | 14 +- .../ExecuteThreadMessageTest.cs | 107 +- .../MeshNodeReferenceSingleInstanceTest.cs | 8 +- .../MeshWeaver.Threading.Test.csproj | 3 + .../StreamingAreaTest.cs | 2 - .../StreamingRecursionTest.cs | 86 + .../ThreadCreationTest.cs | 11 +- .../ThreadExecutionPersistenceTest.cs | 90 +- .../ThreadResumeTest.cs | 82 +- .../ThreadTestHelper.cs | 103 + .../ToolCallingTest.cs | 24 +- .../ToolCallsVisibilityTest.cs | 10 +- .../appsettings.json | 8 + .../MeshWeaver.Tools.CosmosImport.csproj | 1 + .../MeshWeaver.Tools.PostgreSqlImport.csproj | 1 + 250 files changed, 12767 insertions(+), 25255 deletions(-) delete mode 100644 samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs delete mode 100644 samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs delete mode 100644 samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs create mode 100644 samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv create mode 100644 samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv create mode 100644 samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv create mode 100644 src/MeshWeaver.AI/InternalsVisibleTo.cs delete mode 100644 src/MeshWeaver.AI/Layout/ThreadsLayoutArea.cs create mode 100644 src/MeshWeaver.AI/ThreadMessageHandlers.cs create mode 100644 src/MeshWeaver.ContentCollections/DocSharpContentTransformer.cs create mode 100644 src/MeshWeaver.ContentCollections/IContentTransformer.cs create mode 100644 src/MeshWeaver.Documentation/Data/Architecture/AsynchronousCalls.md create mode 100644 src/MeshWeaver.Hosting.Orleans/OrleansMeshChangeFeed.cs create mode 100644 src/MeshWeaver.Hosting.Orleans/PathCacheInvalidatorGrain.cs create mode 100644 src/MeshWeaver.Hosting/MeshChangeFeed.cs create mode 100644 src/MeshWeaver.Hosting/PathResolutionService.cs create mode 100644 src/MeshWeaver.Layout/ThreadMessageActionRequests.cs create mode 100644 src/MeshWeaver.Mesh.Contract/Services/IMeshChangeFeed.cs create mode 100644 src/MeshWeaver.Messaging.Contract/HeartBeatEvent.cs create mode 100644 test/MeshWeaver.ContentCollections.Test/DocxConversionTest.cs create mode 100644 test/MeshWeaver.Hosting.Monolith.Test/MeshChangeFeedTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/DelegationCompletionTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansApiTokenTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansAutoExecuteTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansChatHistoryTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationFlowTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationStartTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansMeshChangeFeedTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansNodeChangePropagationTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansPortalFlowTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansReentrancyTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/OrleansSubThreadRoutingTest.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/SharedOrleansFixture.cs create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/appsettings.json create mode 100644 test/MeshWeaver.Hosting.Orleans.Test/xunit.runner.json create mode 100644 test/MeshWeaver.Hosting.PostgreSql.Test/ThreadPathResolutionTest.cs create mode 100644 test/MeshWeaver.NodeOperations.Test/ApiTokenAccessTest.cs create mode 100644 test/MeshWeaver.NodeOperations.Test/MeshPluginAccessContextTest.cs create mode 100644 test/MeshWeaver.Threading.Test/AccessContextToolCallTest.cs create mode 100644 test/MeshWeaver.Threading.Test/AutoExecuteFlowTest.cs create mode 100644 test/MeshWeaver.Threading.Test/BinaryAttachmentTest.cs create mode 100644 test/MeshWeaver.Threading.Test/ChatHistoryTest.cs create mode 100644 test/MeshWeaver.Threading.Test/DelegationFailureTest.cs create mode 100644 test/MeshWeaver.Threading.Test/StreamingRecursionTest.cs create mode 100644 test/MeshWeaver.Threading.Test/ThreadTestHelper.cs create mode 100644 test/MeshWeaver.Threading.Test/appsettings.json diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml index 05fad7ace..fdb85931d 100644 --- a/.github/workflows/dotnet-test.yml +++ b/.github/workflows/dotnet-test.yml @@ -17,9 +17,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: 10.0.x - name: Restore workloads @@ -57,7 +57,7 @@ jobs: files: | test/**/*.trx - name: "Upload artifact: Test Results" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 if: always() with: name: testResults diff --git a/.github/workflows/publish-github.yml b/.github/workflows/publish-github.yml index 6527bd9a4..9312e0714 100644 --- a/.github/workflows/publish-github.yml +++ b/.github/workflows/publish-github.yml @@ -16,10 +16,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '9.x' diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index 9bdb8c51b..f399b4209 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -15,10 +15,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '9.x' diff --git a/.gitignore b/.gitignore index c213b8e7e..1191e9994 100644 --- a/.gitignore +++ b/.gitignore @@ -381,3 +381,5 @@ samples/Graph/Data/VUser/ **/_useractivity/ /memex/Azurite/Data/__blobstorage__/901d58e2-347d-4ffb-b363-14b77f399fe7 /memex/Azurite/Data/__blobstorage__/cb6d455a-1fd9-4c04-bef4-96453cf54208 +/memex/Azurite/Data/__blobstorage__/1925247c-9d12-4714-81be-90fb21037ea8 +/memex/Azurite/Data/__blobstorage__/4bfa3197-30d4-4325-9c7f-71b21bd3e418 diff --git a/CLAUDE.md b/CLAUDE.md index ee4520b1f..a7c9bf04c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,10 @@ This file provides guidance to AI agents when working with code in this repository. +## Git Workflow + +**NEVER commit or push automatically.** Always wait for the user to explicitly ask for a commit or push. Present changes for review first. + ## Documentation Documentation is embedded in `src/MeshWeaver.Documentation/` and served under the `Doc/` namespace at runtime. diff --git a/Directory.Packages.props b/Directory.Packages.props index 07dc40503..085990585 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -22,9 +22,9 @@ - + - + @@ -37,6 +37,7 @@ + @@ -69,10 +70,10 @@ - - + + - + @@ -91,10 +92,10 @@ - - - - + + + + @@ -118,16 +119,16 @@ - + - - + + - - + + @@ -141,7 +142,7 @@ - + diff --git a/dist/templates/aspire/Memex.AppHost/Program.cs b/dist/templates/aspire/Memex.AppHost/Program.cs index 3591c12b7..eeef90722 100644 --- a/dist/templates/aspire/Memex.AppHost/Program.cs +++ b/dist/templates/aspire/Memex.AppHost/Program.cs @@ -115,10 +115,13 @@ // --- Database Migration --- var dbMigration = builder .AddProject("db-migration") - .WithReference(appInsights) - .WaitFor(appInsights) .WithEnvironment("Embedding__Model", embeddingModel); +if (!useLocalDb) +{ + dbMigration.WithReference(appInsights).WaitFor(appInsights); +} + // --- Portal (co-hosted Orleans silo + web) --- var portal = builder .AddProject(isDeployed ? $"memex-{mode}" : "memex-local") diff --git a/memex/Memex.Portal.Shared/Authentication/ApiTokenService.cs b/memex/Memex.Portal.Shared/Authentication/ApiTokenService.cs index 42807a4ad..8d579228d 100644 --- a/memex/Memex.Portal.Shared/Authentication/ApiTokenService.cs +++ b/memex/Memex.Portal.Shared/Authentication/ApiTokenService.cs @@ -76,6 +76,14 @@ internal class ApiTokenService(IMeshService nodeFactory, IMeshService meshQuery, return (rawToken, created); } + /// + /// Queries nodes using the system identity to bypass access control. + /// ApiTokenService is infrastructure code that needs unrestricted read access. + /// + private IAsyncEnumerable QueryAsSystemAsync(string query, CancellationToken ct = default) + => meshQuery.QueryAsync( + MeshQueryRequest.FromQuery(query, WellKnownUsers.System), ct: ct); + public async Task ValidateTokenAsync(string rawToken) { if (string.IsNullOrEmpty(rawToken) || !rawToken.StartsWith(TokenPrefix)) @@ -85,7 +93,7 @@ internal class ApiTokenService(IMeshService nodeFactory, IMeshService meshQuery, var hashPrefix = hash[..12]; var indexPath = $"{ApiTokenNamespace}/{hashPrefix}"; - var indexNode = await meshQuery.QueryAsync($"path:{indexPath}").FirstOrDefaultAsync(); + var indexNode = await QueryAsSystemAsync($"path:{indexPath}").FirstOrDefaultAsync(); if (indexNode == null) return null; @@ -98,7 +106,7 @@ internal class ApiTokenService(IMeshService nodeFactory, IMeshService meshQuery, // New format: index pointer -> follow to user namespace if (!string.Equals(index.TokenHash, hash, StringComparison.OrdinalIgnoreCase)) return null; - tokenNode = await meshQuery.QueryAsync($"path:{index.TokenPath}").FirstOrDefaultAsync(); + tokenNode = await QueryAsSystemAsync($"path:{index.TokenPath}").FirstOrDefaultAsync(); apiToken = tokenNode?.Content as ApiToken ?? ExtractApiToken(tokenNode); } else @@ -143,7 +151,7 @@ internal class ApiTokenService(IMeshService nodeFactory, IMeshService meshQuery, public async Task RevokeTokenAsync(string tokenNodePath) { - var node = await meshQuery.QueryAsync($"path:{tokenNodePath}").FirstOrDefaultAsync(); + var node = await QueryAsSystemAsync($"path:{tokenNodePath}").FirstOrDefaultAsync(); if (node == null) return false; @@ -162,7 +170,7 @@ public async Task RevokeTokenAsync(string tokenNodePath) var indexPath = $"{ApiTokenNamespace}/{hashPrefix}"; if (tokenNodePath != indexPath) { - var indexNode = await meshQuery.QueryAsync($"path:{indexPath}").FirstOrDefaultAsync(); + var indexNode = await QueryAsSystemAsync($"path:{indexPath}").FirstOrDefaultAsync(); if (indexNode != null) { hub.Post(new DeleteNodeRequest(indexPath)); @@ -179,8 +187,10 @@ public async Task> GetTokensForUserAsync(string userId) var tokens = new List(); // Query user-scoped tokens (new format) + // ApiToken is a satellite type (MainNode != Path), so we need nodeType: condition + // to trigger GetAllChildrenAsync which includes satellites in the results. var userTokenNamespace = $"User/{userId}/{ApiTokenNamespace}"; - await foreach (var node in meshQuery.QueryAsync($"namespace:{userTokenNamespace}")) + await foreach (var node in QueryAsSystemAsync($"namespace:{userTokenNamespace} nodeType:{NodeTypeApiToken}")) { var apiToken = node.Content as ApiToken ?? ExtractApiToken(node); if (apiToken == null) @@ -199,7 +209,7 @@ public async Task> GetTokensForUserAsync(string userId) } // Fallback: also check legacy tokens at top-level ApiToken namespace - await foreach (var node in meshQuery.QueryAsync($"namespace:{ApiTokenNamespace}")) + await foreach (var node in QueryAsSystemAsync($"namespace:{ApiTokenNamespace} nodeType:{NodeTypeApiToken}")) { var apiToken = node.Content as ApiToken ?? ExtractApiToken(node); if (apiToken == null || apiToken.UserId != userId) diff --git a/memex/Memex.Portal.Shared/OrganizationNodeType.cs b/memex/Memex.Portal.Shared/OrganizationNodeType.cs index d4c4d42a7..6f9b470d7 100644 --- a/memex/Memex.Portal.Shared/OrganizationNodeType.cs +++ b/memex/Memex.Portal.Shared/OrganizationNodeType.cs @@ -44,7 +44,8 @@ public record Organization /// /// Provides configuration for Organization nodes in the graph. -/// Access rules: public read. Create/Update/Delete require Admin role via ISecurityService. +/// Access rules: Read/Create/Update/Delete controlled by partition-level permissions via ISecurityService. +/// Excluded from search to prevent cross-partition data leakage. /// public static class OrganizationNodeType { @@ -65,7 +66,8 @@ public static TBuilder AddOrganizationType(this TBuilder builder) wher sp.GetService()?.CreateLogger())); return services; }); - builder.ConfigureNodeTypeAccess(a => a.WithPublicRead(NodeType)); + // Organization instances are NOT publicly readable — partition access controls visibility. + // The type definition itself remains visible; instances are filtered by user permissions. return builder; } @@ -87,7 +89,6 @@ public IEnumerable GetStaticNodes() HubConfiguration = config => config .AddMeshDataSource(source => source .WithContentType()) - .WithPublicRead() .AddContentCollections() .AddNodeTypeLayoutAreas() .AddLayout(layout => layout @@ -150,12 +151,12 @@ private class OrganizationAccessRule(ISecurityService securityService) : INodeTy public async Task HasAccessAsync(NodeValidationContext context, string? userId, CancellationToken ct = default) { - if (context.Operation == NodeOperation.Read) - return true; - if (string.IsNullOrEmpty(userId)) return false; + if (context.Operation == NodeOperation.Read) + return await securityService.HasPermissionAsync(context.Node.Path, userId, Permission.Read, ct); + if (context.Operation == NodeOperation.Create) { var parentPath = context.Node.GetParentPath() ?? context.Node.Path; diff --git a/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json b/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json index ce0ba8495..6e539eb49 100644 --- a/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json +++ b/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json @@ -5,7 +5,9 @@ "Default": "Warning", "Microsoft.AspNetCore": "Warning", "MeshWeaver": "Warning", - "MeshWeaver.AI": "Warning", + "MeshWeaver.AI": "Information", + "MeshWeaver.Layout.ConvertJson": "Warning", + "MeshWeaver.Messaging.Hub.MessageHub": "Warning", "Azure.Core": "Warning", "Orleans": "Warning", "Memex": "Warning", diff --git a/memex/aspire/Memex.Portal.Distributed/appsettings.json b/memex/aspire/Memex.Portal.Distributed/appsettings.json index eba7ad520..71029baf8 100644 --- a/memex/aspire/Memex.Portal.Distributed/appsettings.json +++ b/memex/aspire/Memex.Portal.Distributed/appsettings.json @@ -1,7 +1,9 @@ { "Logging": { "LogLevel": { - "Default": "Warning" + "Default": "Warning", + "MeshWeaver.AI": "Information", + "MeshWeaver.Hosting.Orleans.RoutingGrain": "Information" } }, "AllowedHosts": "*", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json b/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json index 3cb9c95cf..d2c18ef1a 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/Analysis.json @@ -12,7784 +12,6 @@ "$type": "AnalysisContent", "id": "Analysis", "name": "AmericasIns Profitability Analysis", - "description": "Interactive profitability analysis for AmericasIns with local lines of business, estimates vs actuals, and quarterly trends.", - "datacube": [ - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 10885000.0, - "actual": 11102700.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1428000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14280000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 32342613.0, - "actual": 32989465.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4896000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48960000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4656000.0, - "actual": 4749120.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1020000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10200000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 23031067.0, - "actual": 23491688.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3366000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 33660000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 51605987.0, - "actual": 52638107.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6324000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 65720000.0, - "actual": 67034400.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21318000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3876000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38760000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11566800.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1836000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18360000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 26493600.0, - "actual": 27023472.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4284000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 42840000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 9902200.0, - "actual": 9605134.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1358000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13580000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 31113813.0, - "actual": 30180399.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4656000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46560000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5136000.0, - "actual": 4981920.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 970000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9700000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 21183067.0, - "actual": 20547575.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3201000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 32010000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 48360101.0, - "actual": 46909298.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6014000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 63240000.0, - "actual": 61342800.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20273000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3686000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36860000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 10999800.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1746000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17460000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 25384800.0, - "actual": 24623256.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4074000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 40740000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 8919400.0, - "actual": 9365370.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1470000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14700000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 29885013.0, - "actual": 31379264.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 5040000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 50400000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5424000.0, - "actual": 5695200.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1050000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10500000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 20443867.0, - "actual": 21466060.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3465000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 34650000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 41991600.0, - "actual": 44091180.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6510000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 58900000.0, - "actual": 61845000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21945000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3990000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39900000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11907000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1890000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18900000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 23610720.0, - "actual": 24791256.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4410000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 44100000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 7936600.0, - "actual": 7777868.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1372000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13720000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 29393493.0, - "actual": 28805623.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4704000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 47040000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5904000.0, - "actual": 5785920.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 980000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9800000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 21737467.0, - "actual": 21302718.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3234000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 32340000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 40578139.0, - "actual": 39766576.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6076000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 54560000.0, - "actual": 53468800.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20482000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3724000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 37240000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11113200.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1764000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17640000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 22723680.0, - "actual": 22269206.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4116000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 41160000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 7936600.0, - "actual": 8015966.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1414000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14140000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 31113813.0, - "actual": 31424951.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4848000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48480000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5424000.0, - "actual": 5478240.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1010000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10100000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 22291867.0, - "actual": 22514786.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3333000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 33330000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 41745056.0, - "actual": 42162507.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6262000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 57660000.0, - "actual": 58236600.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21109000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3838000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38380000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11453400.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1818000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18180000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 24276000.0, - "actual": 24518760.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4242000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 42420000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 8264200.0, - "actual": 7933632.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1344000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13440000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 29885013.0, - "actual": 28689612.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4608000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46080000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4944000.0, - "actual": 4746240.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 960000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9600000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 21183067.0, - "actual": 20335744.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3168000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 31680000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 39998842.0, - "actual": 38398888.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 5952000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 55800000.0, - "actual": 53568000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20064000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3648000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36480000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 10886400.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1728000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17280000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 23167200.0, - "actual": 22240512.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4032000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 40320000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 8919400.0, - "actual": 9186982.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1442000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14420000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 28656213.0, - "actual": 29515899.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4944000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 49440000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4464000.0, - "actual": 4597920.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1030000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10300000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 19335067.0, - "actual": 19915119.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3399000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 33990000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 36855814.0, - "actual": 37961488.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6386000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 60760000.0, - "actual": 62582800.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21527000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3914000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39140000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11680200.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1854000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18540000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 25384800.0, - "actual": 26146344.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4326000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 43260000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 9574600.0, - "actual": 9478854.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1386000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13860000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 27427413.0, - "actual": 27153139.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4752000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 47520000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4176000.0, - "actual": 4134240.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 990000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9900000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 18595867.0, - "actual": 18409908.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3267000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 32670000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 35725957.0, - "actual": 35368697.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6138000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 62000000.0, - "actual": 61380000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20691000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3762000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 37620000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11226600.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1782000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17820000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 26493600.0, - "actual": 26228664.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4158000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 41580000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 10557400.0, - "actual": 10979696.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1456000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14560000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 27918933.0, - "actual": 29035690.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4992000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 49920000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4320000.0, - "actual": 4492800.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1040000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10400000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 18965467.0, - "actual": 19724086.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3432000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 34320000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 37044884.0, - "actual": 38526679.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6448000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 64480000.0, - "actual": 67059200.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21736000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3952000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39520000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11793600.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1872000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18720000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 27158880.0, - "actual": 28245235.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4368000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 43680000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 11212600.0, - "actual": 10651970.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1330000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13300000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 29885013.0, - "actual": 28390762.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4560000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 45600000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4656000.0, - "actual": 4423200.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 950000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9500000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 22291867.0, - "actual": 21177274.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3135000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 31350000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 39464930.0, - "actual": 37491684.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 5890000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 66960000.0, - "actual": 63612000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 19855000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3610000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36100000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 10773000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1710000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17100000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 27602400.0, - "actual": 26222280.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 3990000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 39900000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 11867800.0, - "actual": 12579868.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1484000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14840000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 31113813.0, - "actual": 32980642.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 5088000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 50880000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4944000.0, - "actual": 5240640.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1060000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10600000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 23031067.0, - "actual": 24412931.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3498000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 34980000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 44087216.0, - "actual": 46732449.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6572000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 69440000.0, - "actual": 73606400.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 22154000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 4028000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 40280000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 12020400.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1908000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 19080000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 28045920.0, - "actual": 29728675.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4452000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 44520000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 11540200.0, - "actual": 11309396.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1372000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13720000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 31851093.0, - "actual": 31214071.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4704000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 47040000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4464000.0, - "actual": 4374720.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 980000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9800000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 24139867.0, - "actual": 23657070.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3234000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 32340000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 49346273.0, - "actual": 48359348.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6076000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 68200000.0, - "actual": 66836000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20482000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3724000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 37240000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11113200.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1764000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17640000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 27602400.0, - "actual": 27050352.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4116000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 41160000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 10885000.0, - "actual": 10993850.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1414000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14140000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 32342613.0, - "actual": 32666039.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4848000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48480000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4656000.0, - "actual": 4702560.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1010000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10100000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 23031067.0, - "actual": 23261378.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3333000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 33330000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 51605987.0, - "actual": 52122047.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6262000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 65720000.0, - "actual": 66377200.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21109000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3838000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38380000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11453400.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1818000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18180000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 26493600.0, - "actual": 26758536.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4242000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 42420000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 9902200.0, - "actual": 9605134.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1358000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13580000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 31113813.0, - "actual": 30180399.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4656000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46560000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5136000.0, - "actual": 4981920.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 970000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9700000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 21183067.0, - "actual": 20547575.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3201000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 32010000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 48360101.0, - "actual": 46909298.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6014000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 63240000.0, - "actual": 61342800.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20273000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3686000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36860000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 10999800.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1746000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17460000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 25384800.0, - "actual": 24623256.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4074000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 40740000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 8919400.0, - "actual": 9186982.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1442000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14420000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 29885013.0, - "actual": 30781563.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4944000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 49440000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5424000.0, - "actual": 5586720.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1030000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10300000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 20443867.0, - "actual": 21057183.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3399000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 33990000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 41991600.0, - "actual": 43251348.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6386000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 58900000.0, - "actual": 60667000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21527000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3914000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39140000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11680200.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1854000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18540000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 23610720.0, - "actual": 24319042.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4326000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 43260000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 7936600.0, - "actual": 7936600.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1400000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 29393493.0, - "actual": 29393493.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4800000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5904000.0, - "actual": 5904000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 21737467.0, - "actual": 21737467.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3300000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 33000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 40578139.0, - "actual": 40578139.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6200000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 54560000.0, - "actual": 54560000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20900000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3800000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11340000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1800000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 22723680.0, - "actual": 22723680.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4200000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 42000000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 7936600.0, - "actual": 7619136.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1344000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 13440000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 31113813.0, - "actual": 29869260.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4608000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46080000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 5424000.0, - "actual": 5207040.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 960000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 9600000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 22291867.0, - "actual": 21400192.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3168000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 31680000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 41745056.0, - "actual": 40075254.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 5952000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 57660000.0, - "actual": 55353600.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 20064000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3648000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36480000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 10886400.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1728000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 17280000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 24276000.0, - "actual": 23304960.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4032000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 40320000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "CapitalCost", - "estimate": 770000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Claims", - "estimate": 8264200.0, - "actual": 8429484.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExpectedProfit", - "estimate": 700000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "ExternalCost", - "estimate": 1400000.0, - "actual": 1428000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "InternalCost", - "estimate": 1680000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "AGRICULTURE", - "amountType": "Premium", - "estimate": 14000000.0, - "actual": 14280000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Claims", - "estimate": 29885013.0, - "actual": 30482713.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4896000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMMERCIAL", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48960000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "CapitalCost", - "estimate": 550000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Claims", - "estimate": 4944000.0, - "actual": 5042880.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExpectedProfit", - "estimate": 500000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "ExternalCost", - "estimate": 1000000.0, - "actual": 1020000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "InternalCost", - "estimate": 1200000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_TECH", - "amountType": "Premium", - "estimate": 10000000.0, - "actual": 10200000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "CapitalCost", - "estimate": 1815000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Claims", - "estimate": 21183067.0, - "actual": 21606728.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExpectedProfit", - "estimate": 1650000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "ExternalCost", - "estimate": 3300000.0, - "actual": 3366000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "InternalCost", - "estimate": 3960000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "ENERGY_MINING", - "amountType": "Premium", - "estimate": 33000000.0, - "actual": 33660000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "CapitalCost", - "estimate": 3410000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Claims", - "estimate": 39998842.0, - "actual": 40798819.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExpectedProfit", - "estimate": 3100000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "ExternalCost", - "estimate": 6200000.0, - "actual": 6324000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "InternalCost", - "estimate": 7440000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOMEOWNERS", - "amountType": "Premium", - "estimate": 55800000.0, - "actual": 56916000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Claims", - "estimate": 20900000.0, - "actual": 21318000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3876000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_ANN", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38760000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "CapitalCost", - "estimate": 990000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Claims", - "estimate": 11340000.0, - "actual": 11566800.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExpectedProfit", - "estimate": 900000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "ExternalCost", - "estimate": 1800000.0, - "actual": 1836000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "InternalCost", - "estimate": 2160000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN_US", - "amountType": "Premium", - "estimate": 18000000.0, - "actual": 18360000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "CapitalCost", - "estimate": 2310000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Claims", - "estimate": 23167200.0, - "actual": 23630544.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExpectedProfit", - "estimate": 2100000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "ExternalCost", - "estimate": 4200000.0, - "actual": 4284000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "InternalCost", - "estimate": 5040000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "WORKERS_COMP", - "amountType": "Premium", - "estimate": 42000000.0, - "actual": 42840000.0 - } - ] + "description": "Interactive profitability analysis for AmericasIns with local lines of business, estimates vs actuals, and quarterly trends." } } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json index 3b89ad029..3217b529e 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/AGRICULTURE.json @@ -2,7 +2,7 @@ "id": "AGRICULTURE", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Agriculture", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Crop insurance, livestock coverage, and agricultural risk management for North and South American farming operations", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json index 27edc8f4c..69f9de8ef 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/COMMERCIAL.json @@ -2,7 +2,7 @@ "id": "COMMERCIAL", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Commercial Lines", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Multi-peril commercial package policies covering property, liability, and inland marine risks for businesses", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json index e685fe5c7..0cc1a4168 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/CYBER_TECH.json @@ -2,7 +2,7 @@ "id": "CYBER_TECH", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Cyber & Technology", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Standalone cyber liability and technology errors & omissions insurance for US and Americas markets", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json index 6fdc861e3..d2f573dc9 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/ENERGY_MINING.json @@ -2,7 +2,7 @@ "id": "ENERGY_MINING", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Energy & Mining", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Upstream and downstream energy, mining operations, and renewable energy project insurance", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json index 35dd5f2b4..b6b5dcd96 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/HOMEOWNERS.json @@ -2,7 +2,7 @@ "id": "HOMEOWNERS", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Homeowners", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Residential property insurance covering homes, condos, and personal property in the Americas", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json index fac515c3c..135252e3b 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/LIFE_ANN.json @@ -2,7 +2,7 @@ "id": "LIFE_ANN", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Life & Annuity", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Individual and group life insurance, annuities, and retirement products for the Americas market", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json index 52439400c..c29fc28ef 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/SPECIALTY_AVTN_US.json @@ -2,7 +2,7 @@ "id": "SPECIALTY_AVTN_US", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Specialty & Aviation", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "US specialty lines including aviation, space, political risk, and surety for Americas operations", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json index f328ec06b..99a59b46f 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/WORKERS_COMP.json @@ -2,7 +2,7 @@ "id": "WORKERS_COMP", "namespace": "FutuRe/AmericasIns/LineOfBusiness", "name": "Workers Compensation", - "nodeType": "FutuRe/AmericasIns/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Statutory workers compensation and employers liability insurance across US states and territories", "icon": "/static/storage/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs b/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs deleted file mode 100644 index 168782e97..000000000 --- a/samples/Graph/Data/FutuRe/AmericasIns/LineOfBusiness/_Source/ExternalDependencies.cs +++ /dev/null @@ -1,7 +0,0 @@ -// -// Id: ExternalDependencies -// DisplayName: External Dependencies -// - -@@FutuRe/LineOfBusiness/_Source/LineOfBusinessLayoutAreas -@@FutuRe/LineOfBusiness/_Source/LineOfBusiness diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json index ea68af90c..166b32bc5 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-AGRICULTURE-AGRI.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Agriculture", "groupLineOfBusiness": "AGRI", "groupLineOfBusinessName": "Agriculture", - "percentage": 100 + "percentage": 1 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json index f20a2a80e..0defa2973 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Lines", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 25 + "percentage": 0.25 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json index 3c54abcf3..7746e6cf6 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-MARINE.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Lines", "groupLineOfBusiness": "MARINE", "groupLineOfBusinessName": "Marine", - "percentage": 15 + "percentage": 0.15 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json index 3b0ce1f6e..8016a9226 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-COMMERCIAL-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Lines", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 60 + "percentage": 0.6 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json index fedc0fddf..1107a1b5f 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-CYBER.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Cyber & Technology", "groupLineOfBusiness": "CYBER", "groupLineOfBusinessName": "Cyber", - "percentage": 70 + "percentage": 0.7 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json index 4625ba4e0..8d60c9bf8 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-CYBER_TECH-PROF.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Cyber & Technology", "groupLineOfBusiness": "PROF", "groupLineOfBusinessName": "Professional Liability", - "percentage": 30 + "percentage": 0.3 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json index 79979c3a5..f12b2c1d8 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-ENRG.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Energy & Mining", "groupLineOfBusiness": "ENRG", "groupLineOfBusinessName": "Energy", - "percentage": 80 + "percentage": 0.8 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json index a2e273ef4..71eb0eefb 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-ENERGY_MINING-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Energy & Mining", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 20 + "percentage": 0.2 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json index e6da40438..bb07c277f 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Homeowners", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 15 + "percentage": 0.15 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json index 96cb7fdca..53eb76e16 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-HOMEOWNERS-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Homeowners", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 85 + "percentage": 0.85 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json index 7be6b8578..6a9041167 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-LIFE_ANN-LH.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Life & Annuity", "groupLineOfBusiness": "LH", "groupLineOfBusinessName": "Life & Health", - "percentage": 100 + "percentage": 1 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json index 3fbfaedf1..4ca304728 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-AVTN.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "AVTN", "groupLineOfBusinessName": "Aviation", - "percentage": 50 + "percentage": 0.5 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json index 73cfff91a..ff611a545 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-SPECIALTY_AVTN_US-SPEC.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "SPEC", "groupLineOfBusinessName": "Specialty", - "percentage": 50 + "percentage": 0.5 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json index f19927126..7dcdf3226 100644 --- a/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json +++ b/samples/Graph/Data/FutuRe/AmericasIns/TransactionMapping/AME-WORKERS_COMP-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Workers Compensation", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 100 + "percentage": 1 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json b/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json index df0d14afa..21e73c4f5 100644 --- a/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json +++ b/samples/Graph/Data/FutuRe/AsiaRe/Analysis.json @@ -12,7784 +12,6 @@ "$type": "AnalysisContent", "id": "Analysis", "name": "AsiaRe Profitability Analysis", - "description": "Interactive profitability analysis for AsiaRe with local lines of business, estimates vs actuals, and quarterly trends.", - "datacube": [ - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2449442168.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 414330739.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4223423702.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 740820742.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 151590295.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1483392644.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5486579879.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 776345941.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7922360025.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1244238708.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 180057837.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1766145400.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3283070350.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 454046880.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4414776475.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1872000000.0, - "actual": 1925888737.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 241285426.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2404314382.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1120950485.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 213853323.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2125992158.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 5814000000.0, - "actual": 6377621052.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 558217399.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5745175782.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2512257460.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 409737195.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4276811796.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 747215676.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 150933534.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1475802983.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5775373897.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 781695475.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7895824021.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1260356265.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 180562039.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1834064335.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3394873662.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 459766086.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4559292840.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1601130565.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 233459871.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2407425806.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1147089448.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 204705379.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2077143455.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3791038523.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 562406697.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5639076322.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2517950167.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 416728560.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4222794987.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 713777923.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 153929891.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1482570422.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5721190378.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 764609289.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7846187040.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1238670971.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 178698119.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1816497129.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3400595936.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 451537643.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4588114203.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1618387920.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 243974399.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2417722968.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1123316063.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 207674708.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2077240038.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3825141560.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 585147512.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5647044920.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2507839061.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 423917054.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4263229761.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 751077941.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 149629667.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1493737914.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5558324807.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 782872029.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7726642612.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1281126268.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 184296487.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1782917396.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3288527050.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 463433515.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4481892091.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1524545495.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 233478476.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2400914524.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1178326014.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 213680200.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2067210527.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3779418671.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 565951380.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5682252472.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2551069452.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 431871175.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4283348392.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 699061307.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 151986496.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1521646782.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 14040000000.0, - "actual": 15928556084.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 769087419.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7856693635.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1233444459.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 179295465.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1810149249.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3484196563.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 460148029.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4491670267.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1575673147.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 235372587.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2377285349.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1200785916.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 207460404.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2134660739.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3948549483.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 558127103.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5731680485.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2553138812.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 427021387.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4244101814.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 698432941.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 148417405.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1501821220.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5864945426.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 797724184.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7650076744.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1253197424.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 175225592.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1823879918.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3482367332.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 438812643.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4568041728.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1521837722.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 243752671.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2398655084.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1132213371.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 209688558.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2122330092.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3841908760.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 582737210.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5711355219.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2487098518.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 420990261.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4187087174.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 709986301.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 148305447.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1513795864.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5739497214.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 777103084.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7954486599.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1234397223.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 177026731.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1801265461.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3386825443.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 442713098.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4470855401.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1522059937.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 241887883.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2373140869.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1204010809.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 214531406.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2077231110.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3833520477.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 575779040.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5602155476.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2471074069.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 430974959.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4151991784.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 725625851.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 152561575.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1504262586.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5533067366.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 761136362.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7895939063.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1264896725.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 179643866.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1795035685.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3409484315.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 463072461.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4541233653.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1563447136.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 237685958.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2361448116.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1143325845.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 206096632.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2130380493.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3890537059.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 562426244.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5688283889.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2630530345.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 418566895.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4157967483.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 730098738.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 145955295.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1521680946.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5823130473.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 801949025.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7955776130.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1307748530.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 176396160.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1830698423.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3287042281.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 447328088.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4497415403.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1560495845.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 246988447.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2357628998.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1192798124.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 209433105.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2080277057.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 4056565054.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 586943456.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5682445707.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2589231108.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 411300880.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4209369078.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 754197659.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 150712623.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1487802470.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5783570460.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 759275335.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7813164903.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1272887319.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 183809375.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1806060787.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3486051500.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 438663010.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4438337891.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1587460381.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 242523061.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2369839196.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1131427523.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 214917620.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2077757127.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3944068499.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 574082848.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5642137099.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2562068334.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 420574124.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4186429786.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 710165330.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 151945726.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1526082375.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5625338665.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 788035102.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7718470017.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1254070661.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 182720137.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1785599790.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3352187263.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 463458270.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4423057761.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1872000000.0, - "actual": 1902928672.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 235869422.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2447625259.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1206583167.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 214798889.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2080276835.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 5814000000.0, - "actual": 6005169587.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 558294942.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5786473615.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2586233649.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 422814280.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4256069152.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 736069036.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 145570408.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1529233984.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5582024886.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 787646592.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7898936490.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1235736544.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 175846630.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1831602960.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3377478778.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 443853402.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4429266476.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1872000000.0, - "actual": 2003447501.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 235731801.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2410063663.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1144742113.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 209855501.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2111275989.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 5814000000.0, - "actual": 6837535727.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 556056608.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5792416720.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2500178733.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 407489351.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4187160730.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 735097731.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 147857597.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1516267153.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5695378980.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 776615748.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7875264043.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1229784581.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 184137549.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1764696218.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3375445253.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 459034066.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4572707143.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1872000000.0, - "actual": 1914602631.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 234635215.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2407920918.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1203415890.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 213731141.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2083893701.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 5814000000.0, - "actual": 6663456610.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 560084618.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5782240189.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2465123194.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 427058929.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4157920996.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 721807338.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 151085954.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1523048082.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5865296943.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 797063547.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7692220642.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1303925789.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 184119295.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1834286834.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3426320775.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 445469008.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4414461545.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1613318945.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 245242522.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2441358325.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1145002848.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 213620919.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2126102943.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 4030161476.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 582263889.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5610645803.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2609023860.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 418999642.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4153368865.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 744211901.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 147548359.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1488311452.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5534289351.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 771962659.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7651383304.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1319662422.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 177614550.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1826233412.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3336574322.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 462991042.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4525466713.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1630416795.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 234460921.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2403476710.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1136849666.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 215827932.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2139513651.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3793333462.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 567762081.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5646526331.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2507637347.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 422676463.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4238395570.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 720587257.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 150689292.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1500685384.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5765963052.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 756679152.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7723473422.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1276475961.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 182369844.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1830641412.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3408755434.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 446333980.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4543551014.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1596096863.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 237554881.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2358717486.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1198706612.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 212768904.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2084368914.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3855622988.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 566867037.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5654473477.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2504004089.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 410607653.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4183603265.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 752564947.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 151595862.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1495226780.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5724058541.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 770684454.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7925675330.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1222240919.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 177698668.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1803451479.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3384607946.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 454177052.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4487379867.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1568381543.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 235877300.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2396638866.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1203619108.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 213729912.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2097747640.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3786013400.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 570528459.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5624689638.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "CapitalCost", - "estimate": 231000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Claims", - "estimate": 2520000000.0, - "actual": 2511973952.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExpectedProfit", - "estimate": 210000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "ExternalCost", - "estimate": 420000000.0, - "actual": 428024271.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "InternalCost", - "estimate": 504000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CONSTRUCTION_ENG", - "amountType": "Premium", - "estimate": 4200000000.0, - "actual": 4222334064.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "CapitalCost", - "estimate": 82500000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Claims", - "estimate": 720000000.0, - "actual": 737153031.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExpectedProfit", - "estimate": 75000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "ExternalCost", - "estimate": 150000000.0, - "actual": 147521766.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "InternalCost", - "estimate": 180000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "CYBER_DIGITAL", - "amountType": "Premium", - "estimate": 1500000000.0, - "actual": 1515068288.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "CapitalCost", - "estimate": 429000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Claims", - "estimate": 5616000000.0, - "actual": 5458493838.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExpectedProfit", - "estimate": 390000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "ExternalCost", - "estimate": 780000000.0, - "actual": 768058631.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "InternalCost", - "estimate": 936000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "EARTHQUAKE_VOLCANIC", - "amountType": "Premium", - "estimate": 7800000000.0, - "actual": 7706128539.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "CapitalCost", - "estimate": 99000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Claims", - "estimate": 1260000000.0, - "actual": 1307853560.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExpectedProfit", - "estimate": 90000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "ExternalCost", - "estimate": 180000000.0, - "actual": 175386545.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "InternalCost", - "estimate": 216000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MICRO_HEALTH_PA", - "amountType": "Premium", - "estimate": 1800000000.0, - "actual": 1798209817.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "CapitalCost", - "estimate": 247500000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Claims", - "estimate": 3330000000.0, - "actual": 3397869497.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExpectedProfit", - "estimate": 225000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "ExternalCost", - "estimate": 450000000.0, - "actual": 441749751.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "InternalCost", - "estimate": 540000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR_TPL", - "amountType": "Premium", - "estimate": 4500000000.0, - "actual": 4484599382.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "CapitalCost", - "estimate": 132000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Claims", - "estimate": 1560000000.0, - "actual": 1574898271.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExpectedProfit", - "estimate": 120000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "ExternalCost", - "estimate": 240000000.0, - "actual": 236313376.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "InternalCost", - "estimate": 288000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "PADDY_CROP", - "amountType": "Premium", - "estimate": 2400000000.0, - "actual": 2418850008.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "CapitalCost", - "estimate": 115500000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Claims", - "estimate": 1155000000.0, - "actual": 1120862341.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExpectedProfit", - "estimate": 105000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "ExternalCost", - "estimate": 210000000.0, - "actual": 213162152.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "InternalCost", - "estimate": 252000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRADE_CREDIT", - "amountType": "Premium", - "estimate": 2100000000.0, - "actual": 2113108873.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "CapitalCost", - "estimate": 313500000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Claims", - "estimate": 3876000000.0, - "actual": 3792770589.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExpectedProfit", - "estimate": 285000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "ExternalCost", - "estimate": 570000000.0, - "actual": 567440000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "InternalCost", - "estimate": 684000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TYPHOON_FLOOD", - "amountType": "Premium", - "estimate": 5700000000.0, - "actual": 5761570531.0 - } - ] + "description": "Interactive profitability analysis for AsiaRe with local lines of business, estimates vs actuals, and quarterly trends." } } diff --git a/samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs b/samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs deleted file mode 100644 index 168782e97..000000000 --- a/samples/Graph/Data/FutuRe/AsiaRe/LineOfBusiness/_Source/ExternalDependencies.cs +++ /dev/null @@ -1,7 +0,0 @@ -// -// Id: ExternalDependencies -// DisplayName: External Dependencies -// - -@@FutuRe/LineOfBusiness/_Source/LineOfBusinessLayoutAreas -@@FutuRe/LineOfBusiness/_Source/LineOfBusiness diff --git a/samples/Graph/Data/FutuRe/DataDistribution.md b/samples/Graph/Data/FutuRe/DataDistribution.md index 788b08497..d27a707d6 100644 --- a/samples/Graph/Data/FutuRe/DataDistribution.md +++ b/samples/Graph/Data/FutuRe/DataDistribution.md @@ -19,35 +19,42 @@ Each business unit owns its data. The group hub doesn't store copies — it read ```mermaid graph LR subgraph EuropeRe Domain - EU_NODE[Analysis Node
EUR datacube] + EU_CSV[Datacube EUR amounts] + EU_SVC[IContentService] end subgraph AmericasIns Domain - AM_NODE[Analysis Node
USD datacube] + AM_CSV[Datacube USD amounts] + AM_SVC[IContentService] end subgraph AsiaRe Domain - AS_NODE[Analysis Node
JPY datacube] + AS_CSV[Datacube JPY amounts] + AS_SVC[IContentService] end + EU_CSV --> EU_SVC + AM_CSV --> AM_SVC + AS_CSV --> AS_SVC + subgraph Group Hub PART[PartitionedHubDataSource] MAP[TransactionMapping + FX Conversion] AGG[Consolidated View] end - EU_NODE --> PART - AM_NODE --> PART - AS_NODE --> PART + EU_SVC --> PART + AM_SVC --> PART + AS_SVC --> PART PART --> MAP --> AGG classDef eu fill:#e8f0fe,stroke:#4285f4,color:#333 classDef am fill:#fce8e6,stroke:#ea4335,color:#333 classDef asia fill:#fef7e0,stroke:#fbbc04,color:#333 classDef hub fill:#e6f4ea,stroke:#34a853,color:#333 - class EU_NODE eu - class AM_NODE am - class AS_NODE asia + class EU_CSV,EU_SVC eu + class AM_CSV,AM_SVC am + class AS_CSV,AS_SVC asia class PART,MAP,AGG hub ``` @@ -92,11 +99,12 @@ Here's what actually happens when the group dashboard loads. No manual orchestra ```mermaid graph TD - NODE[BU Analysis Node
embedded datacube] - PARSE[LoadLocalDataCube reads from node content] + CSV[BU Data] + CONTENT[IContentService reads raw bytes] + PARSE[LoadLocalDataCube parses data] ENRICH[CombineLatest enriches with LoB names] - NODE --> PARSE --> ENRICH + CSV --> CONTENT --> PARSE --> ENRICH ENRICH --> PHDS[PartitionedHubDataSource merges BU streams] @@ -116,7 +124,7 @@ graph TD classDef process fill:#fff3e0,stroke:#f57c00,color:#333 classDef ref fill:#f3e8fd,stroke:#9c27b0,color:#333 classDef output fill:#e6f4ea,stroke:#34a853,color:#333 - class NODE data + class CSV,CONTENT data class PARSE,ENRICH,PHDS,COMBINE,AGG process class MAPPINGS,FX,LOBS ref class CHARTS output @@ -126,7 +134,7 @@ graph TD ## Key Design Decisions -**BU data ownership** — each BU's Analysis node embeds its own datacube as structured content within the MeshNode. EuropeRe's actuary updates their data directly; the group hub never touches it. This works identically across deployment modes — filesystem, PostgreSQL, or Cosmos DB — because MeshNodes are the universal storage unit. +**Domain ownership** — each BU manages its own data. EuropeRe's actuary updates their data directly; the group never touches it. **Stream composition over data copying** — `PartitionedHubDataSource` reads from BU hubs as live `IObservable` streams. When EuropeRe's data changes, the group view updates automatically — no rebuild, no re-import. @@ -140,9 +148,7 @@ graph TD ) ``` -**No intermediate state** — there are no staging tables, no materialized views, no cache invalidation problems. The only persistent storage is the BU's own data (embedded in its Analysis node) and the mapping rule definitions. - -**Deployment-mode independence** — datacube data is embedded in MeshNode content, not in external files. This means the same FutuRe configuration works in monolith mode (filesystem), distributed mode (PostgreSQL/Azure), and test mode — no special file system setup required. +**No intermediate state** — there are no staging tables, no materialized views, no cache invalidation problems. The only persistent storage is the BU's own data and the mapping rule definitions. --- diff --git a/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json b/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json index 97338b496..a005c1b36 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/Analysis.json @@ -12,7784 +12,6 @@ "$type": "AnalysisContent", "id": "Analysis", "name": "EuropeRe Profitability Analysis", - "description": "Interactive profitability analysis for EuropeRe with local lines of business, estimates vs actuals, and quarterly trends.", - "datacube": [ - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 30760000.0, - "actual": 31375200.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4590000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 45900000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 56568065.0, - "actual": 57699426.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7650000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 78750000.0, - "actual": 80325000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 24418800.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3876000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38760000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 28396800.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4896000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48960000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 40577778.0, - "actual": 41389334.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5610000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 56100000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 16065000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2550000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 25500000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 15273244.0, - "actual": 15578709.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3264000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 32640000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 14774222.0, - "actual": 15069706.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2244000.0 - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-09", - "quarter": "Q3-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22440000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 27250000.0, - "actual": 26432500.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4365000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 43650000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 52717205.0, - "actual": 51135689.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7275000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 75000000.0, - "actual": 72750000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 23221800.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3686000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36860000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 27004800.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4656000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46560000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 39081778.0, - "actual": 37909325.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5335000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 53350000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15277500.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2425000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 24250000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 16860444.0, - "actual": 16354631.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3104000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 31040000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 15390222.0, - "actual": 14928515.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2134000.0 - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-10", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 21340000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 26080000.0, - "actual": 27384000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4725000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 47250000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 47246345.0, - "actual": 49608662.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7875000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 71250000.0, - "actual": 74812500.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 25137000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3990000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39900000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 29232000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 5040000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 50400000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 37585778.0, - "actual": 39465067.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5775000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 57750000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 16537500.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2625000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 26250000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 17654044.0, - "actual": 18536746.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3360000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 33600000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 16006222.0, - "actual": 16806533.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2310000.0 - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-11", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 23100000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 28420000.0, - "actual": 27851600.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4410000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 44100000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 48255484.0, - "actual": 47290374.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7350000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 67500000.0, - "actual": 66150000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 23461200.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3724000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 37240000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 27283200.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4704000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 47040000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 36089778.0, - "actual": 35367982.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5390000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 53900000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15435000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2450000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 24500000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 20034844.0, - "actual": 19634147.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3136000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 31360000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 16622222.0, - "actual": 16289778.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2156000.0 - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2024-12", - "quarter": "Q4-2024", - "year": 2024, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 21560000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 28420000.0, - "actual": 28704200.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4545000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 45450000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 48866345.0, - "actual": 49355008.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7575000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 71250000.0, - "actual": 71962500.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 24179400.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3838000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38380000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 28118400.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4848000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48480000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 36089778.0, - "actual": 36450676.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5555000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 55550000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15907500.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2525000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 25250000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 18447644.0, - "actual": 18632120.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3232000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 32320000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 15390222.0, - "actual": 15544124.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2222000.0 - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-01", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22220000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 27250000.0, - "actual": 26160000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4320000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 43200000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 46879829.0, - "actual": 45004636.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7200000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 69000000.0, - "actual": 66240000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 22982400.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3648000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36480000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 26726400.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4608000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46080000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 34593778.0, - "actual": 33210027.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5280000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 52800000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15120000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2400000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 24000000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 16860444.0, - "actual": 16186026.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3072000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 30720000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 14774222.0, - "actual": 14183253.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2112000.0 - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-02", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 21120000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 24910000.0, - "actual": 25657300.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4635000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 46350000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 42997205.0, - "actual": 44287121.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7725000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 75000000.0, - "actual": 77250000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 24658200.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3914000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39140000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 28675200.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4944000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 49440000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 37585778.0, - "actual": 38713351.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5665000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 56650000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 16222500.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2575000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 25750000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 15273244.0, - "actual": 15731441.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3296000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 32960000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 13542222.0, - "actual": 13948489.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2266000.0 - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-03", - "quarter": "Q1-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22660000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 23740000.0, - "actual": 23502600.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4455000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 44550000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 41621549.0, - "actual": 41205334.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7425000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 76500000.0, - "actual": 75735000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 23700600.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3762000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 37620000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 27561600.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4752000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 47520000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 39081778.0, - "actual": 38690960.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5445000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 54450000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15592500.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2475000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 24750000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 13686044.0, - "actual": 13549184.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3168000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 31680000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 12926222.0, - "actual": 12796960.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2178000.0 - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-04", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 21780000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 24910000.0, - "actual": 25906400.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4680000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 46800000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 40368065.0, - "actual": 41982788.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7800000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 78750000.0, - "actual": 81900000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 24897600.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3952000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39520000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 28953600.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4992000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 49920000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 40577778.0, - "actual": 42200889.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5720000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 57200000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 16380000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2600000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 26000000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 14479644.0, - "actual": 15058830.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3328000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 33280000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 12310222.0, - "actual": 12802631.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2288000.0 - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-05", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22880000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 29590000.0, - "actual": 28110500.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4275000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 42750000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 42354581.0, - "actual": 40236852.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7125000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 81000000.0, - "actual": 76950000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 22743000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3610000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36100000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 26448000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4560000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 45600000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 42073778.0, - "actual": 39970089.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5225000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 52250000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 14962500.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2375000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 23750000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 15273244.0, - "actual": 14509582.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3040000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 30400000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 12926222.0, - "actual": 12279911.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2090000.0 - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-06", - "quarter": "Q2-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 20900000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 30760000.0, - "actual": 32605600.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4770000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 47700000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 47458925.0, - "actual": 50306460.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7950000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 82500000.0, - "actual": 87450000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 25376400.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 4028000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 40280000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 29510400.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 5088000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 50880000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 43569778.0, - "actual": 46183965.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5830000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 58300000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 16695000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2650000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 26500000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 16066844.0, - "actual": 17030855.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3392000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 33920000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 13542222.0, - "actual": 14354755.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2332000.0 - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-07", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 23320000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 31930000.0, - "actual": 31291400.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4410000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 44100000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 52074581.0, - "actual": 51033089.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7350000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 81000000.0, - "actual": 79380000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 23461200.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3724000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 37240000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 27283200.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4704000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 47040000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 42073778.0, - "actual": 41232302.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5390000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 53900000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15435000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2450000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 24500000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 14479644.0, - "actual": 14190051.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3136000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 31360000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 14158222.0, - "actual": 13875058.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2156000.0 - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-08", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 21560000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 30760000.0, - "actual": 31067600.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4545000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 45450000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 56568065.0, - "actual": 57133746.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7575000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 78750000.0, - "actual": 79537500.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 24179400.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3838000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38380000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 28118400.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4848000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48480000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 40577778.0, - "actual": 40983556.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5555000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 55550000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15907500.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2525000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 25250000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 15273244.0, - "actual": 15425976.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3232000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 32320000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 14774222.0, - "actual": 14921964.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2222000.0 - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-09", - "quarter": "Q3-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22220000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 27250000.0, - "actual": 26432500.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4365000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 43650000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 52717205.0, - "actual": 51135689.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7275000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 75000000.0, - "actual": 72750000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 23221800.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3686000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36860000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 27004800.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4656000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46560000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 39081778.0, - "actual": 37909325.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5335000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 53350000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15277500.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2425000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 24250000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 16860444.0, - "actual": 16354631.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3104000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 31040000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 15390222.0, - "actual": 14928515.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2134000.0 - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-10", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 21340000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 26080000.0, - "actual": 26862400.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4635000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 46350000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 47246345.0, - "actual": 48663735.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7725000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 71250000.0, - "actual": 73387500.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 24658200.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3914000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 39140000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 28675200.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4944000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 49440000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 37585778.0, - "actual": 38713351.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5665000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 56650000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 16222500.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2575000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 25750000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 17654044.0, - "actual": 18183665.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3296000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 32960000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 16006222.0, - "actual": 16486409.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2266000.0 - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-11", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22660000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 28420000.0, - "actual": 28420000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4500000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 45000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 48255484.0, - "actual": 48255484.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7500000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 67500000.0, - "actual": 67500000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 23940000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3800000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 27840000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4800000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 36089778.0, - "actual": 36089778.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5500000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 55000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15750000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2500000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 25000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 20034844.0, - "actual": 20034844.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3200000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 32000000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 16622222.0, - "actual": 16622222.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2200000.0 - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2025-12", - "quarter": "Q4-2025", - "year": 2025, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22000000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 28420000.0, - "actual": 27283200.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4320000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 43200000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 48866345.0, - "actual": 46911691.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7200000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 71250000.0, - "actual": 68400000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 22982400.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3648000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 36480000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 26726400.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4608000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 46080000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 36089778.0, - "actual": 34646187.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5280000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 52800000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 15120000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2400000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 24000000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 18447644.0, - "actual": 17709738.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3072000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 30720000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 15390222.0, - "actual": 14774613.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2112000.0 - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2026-01", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 21120000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "CapitalCost", - "estimate": 2475000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Claims", - "estimate": 27250000.0, - "actual": 27795000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExpectedProfit", - "estimate": 2250000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "ExternalCost", - "estimate": 4500000.0, - "actual": 4590000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "InternalCost", - "estimate": 5400000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "COMM_FIRE", - "amountType": "Premium", - "estimate": 45000000.0, - "actual": 45900000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "CapitalCost", - "estimate": 4125000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Claims", - "estimate": 46879829.0, - "actual": 47817426.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExpectedProfit", - "estimate": 3750000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "ExternalCost", - "estimate": 7500000.0, - "actual": 7650000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "InternalCost", - "estimate": 9000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "HOUSEHOLD", - "amountType": "Premium", - "estimate": 69000000.0, - "actual": 70380000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "CapitalCost", - "estimate": 2090000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "Claims", - "estimate": 23940000.0, - "actual": 24418800.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "ExpectedProfit", - "estimate": 1900000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "ExternalCost", - "estimate": 3800000.0, - "actual": 3876000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "InternalCost", - "estimate": 4560000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIABILITY", - "amountType": "Premium", - "estimate": 38000000.0, - "actual": 38760000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "CapitalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Claims", - "estimate": 27840000.0, - "actual": 28396800.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExpectedProfit", - "estimate": 2400000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "ExternalCost", - "estimate": 4800000.0, - "actual": 4896000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "InternalCost", - "estimate": 5760000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "LIFE_HEALTH_EU", - "amountType": "Premium", - "estimate": 48000000.0, - "actual": 48960000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "CapitalCost", - "estimate": 3025000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "Claims", - "estimate": 34593778.0, - "actual": 35285654.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "ExpectedProfit", - "estimate": 2750000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "ExternalCost", - "estimate": 5500000.0, - "actual": 5610000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "InternalCost", - "estimate": 6600000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "MOTOR", - "amountType": "Premium", - "estimate": 55000000.0, - "actual": 56100000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "CapitalCost", - "estimate": 1375000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Claims", - "estimate": 15750000.0, - "actual": 16065000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExpectedProfit", - "estimate": 1250000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "ExternalCost", - "estimate": 2500000.0, - "actual": 2550000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "InternalCost", - "estimate": 3000000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "SPECIALTY_AVTN", - "amountType": "Premium", - "estimate": 25000000.0, - "actual": 25500000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "CapitalCost", - "estimate": 1760000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "Claims", - "estimate": 16860444.0, - "actual": 17197653.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExpectedProfit", - "estimate": 1600000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "ExternalCost", - "estimate": 3200000.0, - "actual": 3264000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "InternalCost", - "estimate": 3840000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TECH_RISK", - "amountType": "Premium", - "estimate": 32000000.0, - "actual": 32640000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "CapitalCost", - "estimate": 1210000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "Claims", - "estimate": 14774222.0, - "actual": 15069706.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExpectedProfit", - "estimate": 1100000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "ExternalCost", - "estimate": 2200000.0, - "actual": 2244000.0 - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "InternalCost", - "estimate": 2640000.0, - "actual": null - }, - { - "month": "2026-02", - "quarter": "Q1-2026", - "year": 2026, - "lineOfBusiness": "TRANSPORT", - "amountType": "Premium", - "estimate": 22000000.0, - "actual": 22440000.0 - } - ] + "description": "Interactive profitability analysis for EuropeRe with local lines of business, estimates vs actuals, and quarterly trends." } } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json index 976cd24d0..e3fc6e965 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/COMM_FIRE.json @@ -2,7 +2,7 @@ "id": "COMM_FIRE", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Commercial Fire", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Commercial and industrial property insurance including engineering risks", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json index 58be656b6..2a9a46c68 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/HOUSEHOLD.json @@ -2,7 +2,7 @@ "id": "HOUSEHOLD", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Household", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Residential property, home contents, and personal liability coverage bundled for European households", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json index c335b9209..b34d5f050 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIABILITY.json @@ -2,7 +2,7 @@ "id": "LIABILITY", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Liability", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "General, products, and employers liability combined with professional indemnity", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json index 1492ddaf7..66a9caeba 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/LIFE_HEALTH_EU.json @@ -2,7 +2,7 @@ "id": "LIFE_HEALTH_EU", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Life & Health", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Life, disability, and health reinsurance for European social security supplement markets", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json index 7f0e2aeb0..bbd2eb015 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/MOTOR.json @@ -2,7 +2,7 @@ "id": "MOTOR", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Motor", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Private and commercial motor vehicle insurance across European markets", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json index c34972a3c..b860f7fe6 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/SPECIALTY_AVTN.json @@ -2,7 +2,7 @@ "id": "SPECIALTY_AVTN", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Specialty & Aviation", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Combined specialty lines and aviation risks for European and global programs", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json index 6fd44e836..2dfe9763b 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TECH_RISK.json @@ -2,7 +2,7 @@ "id": "TECH_RISK", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Technology Risk", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Combined cyber insurance and technology professional liability for digital economy risks", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json index 76c3af574..18ddb05b8 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/TRANSPORT.json @@ -2,7 +2,7 @@ "id": "TRANSPORT", "namespace": "FutuRe/EuropeRe/LineOfBusiness", "name": "Transport", - "nodeType": "FutuRe/EuropeRe/LineOfBusiness", + "nodeType": "FutuRe/LineOfBusiness", "category": "Lines of Business", "description": "Marine cargo, hull, and inland transit insurance for European trade routes", "icon": "/static/storage/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg", diff --git a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs b/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs deleted file mode 100644 index 168782e97..000000000 --- a/samples/Graph/Data/FutuRe/EuropeRe/LineOfBusiness/_Source/ExternalDependencies.cs +++ /dev/null @@ -1,7 +0,0 @@ -// -// Id: ExternalDependencies -// DisplayName: External Dependencies -// - -@@FutuRe/LineOfBusiness/_Source/LineOfBusinessLayoutAreas -@@FutuRe/LineOfBusiness/_Source/LineOfBusiness diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json index 9ce2c166f..cdd5e294d 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-ENRG.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Fire", "groupLineOfBusiness": "ENRG", "groupLineOfBusinessName": "Energy", - "percentage": 20 + "percentage": 0.2 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json index 716d00abf..cea7bd534 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-COMM_FIRE-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Commercial Fire", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 80 + "percentage": 0.8 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json index 582574ff1..0c7ee7395 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Household", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 10 + "percentage": 0.1 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json index e771396fe..87205bb0a 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-HOUSEHOLD-PROP.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Household", "groupLineOfBusiness": "PROP", "groupLineOfBusinessName": "Property", - "percentage": 90 + "percentage": 0.9 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json index 9ba95597f..cf764f6a7 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-CAS.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Liability", "groupLineOfBusiness": "CAS", "groupLineOfBusinessName": "Casualty", - "percentage": 70 + "percentage": 0.7 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json index 1e1d51a13..a8459f8a0 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIABILITY-PROF.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Liability", "groupLineOfBusiness": "PROF", "groupLineOfBusinessName": "Professional Liability", - "percentage": 30 + "percentage": 0.3 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json index 673227e7c..5d5cbfbeb 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-LIFE_HEALTH_EU-LH.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Life & Health", "groupLineOfBusiness": "LH", "groupLineOfBusinessName": "Life & Health", - "percentage": 100 + "percentage": 1 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json index 130d6cbe5..faac77d1b 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS.json @@ -1 +1,18 @@ -{"$type":"MeshNode","id":"EUR-MOTOR-CAS","namespace":"FutuRe/EuropeRe/TransactionMapping","path":"FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS","mainNode":"FutuRe/EuropeRe/TransactionMapping/EUR-MOTOR-CAS","name":"EuropeRe: Motor \u2192 Casualty (100%)","nodeType":"FutuRe/TransactionMapping","icon":"/static/storage/content/FutuRe/icon.svg","lastModified":"2026-03-17T12:52:05.829887+00:00","version":547,"state":"Active","content":{"$type":"TransactionMapping","id":"EUR-MOTOR-CAS","businessUnit":"EuropeRe","localLineOfBusiness":"MOTOR","localLineOfBusinessName":"Motor","groupLineOfBusiness":"CAS","groupLineOfBusinessName":"Casualty","percentage":100}} \ No newline at end of file +{ + "id": "EUR-MOTOR-CAS", + "namespace": "FutuRe/EuropeRe/TransactionMapping", + "name": "EuropeRe: Motor → Casualty (100%)", + "nodeType": "FutuRe/TransactionMapping", + "isPersistent": true, + "content": { + "$type": "TransactionMapping", + "id": "EUR-MOTOR-CAS", + "businessUnit": "EuropeRe", + "localLineOfBusiness": "MOTOR", + "localLineOfBusinessName": "Motor", + "groupLineOfBusiness": "CAS", + "groupLineOfBusinessName": "Casualty", + "percentage": 1 + }, + "icon": "/static/storage/content/FutuRe/icon.svg" +} diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json index 9eab95e60..235bcdd83 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-AVTN.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "AVTN", "groupLineOfBusinessName": "Aviation", - "percentage": 30 + "percentage": 0.3 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json index c5c635382..bc659cc7f 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-SPECIALTY_AVTN-SPEC.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Specialty & Aviation", "groupLineOfBusiness": "SPEC", "groupLineOfBusinessName": "Specialty", - "percentage": 70 + "percentage": 0.7 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json index ba2cb36a1..a6dc48994 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-CYBER.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Technology Risk", "groupLineOfBusiness": "CYBER", "groupLineOfBusinessName": "Cyber", - "percentage": 60 + "percentage": 0.6 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json index b59c1d09e..42bd60410 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TECH_RISK-PROF.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Technology Risk", "groupLineOfBusiness": "PROF", "groupLineOfBusinessName": "Professional Liability", - "percentage": 40 + "percentage": 0.4 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json index bafdd3cb5..f710a794e 100644 --- a/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json +++ b/samples/Graph/Data/FutuRe/EuropeRe/TransactionMapping/EUR-TRANSPORT-MARINE.json @@ -12,7 +12,7 @@ "localLineOfBusinessName": "Transport", "groupLineOfBusiness": "MARINE", "groupLineOfBusinessName": "Marine", - "percentage": 100 + "percentage": 1 }, "icon": "/static/storage/content/FutuRe/icon.svg" } diff --git a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs index d6277f662..355d93f32 100644 --- a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs +++ b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/AnalysisContent.cs @@ -29,27 +29,4 @@ public record AnalysisContent /// Brief description of this analysis scope. ///
public string? Description { get; init; } - - /// - /// Embedded datacube rows for this analysis instance. - /// Each BU's Analysis node stores its own datacube data here, - /// enabling deployment-mode-independent data loading (no CSV/filesystem dependency). - /// - public DataCubeRow[]? Datacube { get; init; } -} - -/// -/// Raw datacube row as stored in MeshNode content. -/// Contains only the base data fields; runtime-derived fields -/// (Id, BusinessUnit, Currency, display names) are added during loading. -/// -public record DataCubeRow -{ - public string Month { get; init; } = string.Empty; - public string Quarter { get; init; } = string.Empty; - public int Year { get; init; } - public string LineOfBusiness { get; init; } = string.Empty; - public string AmountType { get; init; } = string.Empty; - public double Estimate { get; init; } - public double? Actual { get; init; } } diff --git a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs index 55a2cd1d3..5845e2b7d 100644 --- a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs +++ b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/FutuReDataLoader.cs @@ -3,9 +3,11 @@ // DisplayName: FutuRe Data Loader // -using System.Collections.Immutable; +using System.Globalization; +using System.IO; using System.Reactive.Linq; using System.Text.Json; +using MeshWeaver.ContentCollections; using MeshWeaver.Data; using MeshWeaver.Mesh; using MeshWeaver.Mesh.Services; @@ -13,22 +15,23 @@ /// /// Loads profitability data for the FutuRe sample. -/// Local hubs read datacube from their Analysis node's embedded content; -/// the group hub aggregates from local hubs applying transaction mapping rules. +/// Local hubs read CSV via IContentService; the group hub aggregates +/// from local hubs applying transaction mapping rules. /// public static class FutuReDataLoader { // --------------------------------------------------------------- - // Local Data Cube: MeshNode Content + Local LoB Enrichment + // Local Data Cube: CSV + Local LoB Enrichment // --------------------------------------------------------------- /// /// Loads the local data cube for a business unit hub. - /// Reads datacube from the Analysis node's embedded content and enriches - /// with local LoB display names from mesh queries. + /// Reads datacube.csv from "attachments" and enriches with + /// local LoB display names from mesh queries. /// public static IObservable> LoadLocalDataCube(IWorkspace workspace) { + var contentService = workspace.Hub.ServiceProvider.GetRequiredService(); var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); var address = workspace.Hub.Address.ToString(); var segments = address.Split('/'); @@ -47,80 +50,65 @@ public static IObservable> LoadLocalDataCube(IWorksp && val.ValueKind == JsonValueKind.String) buCurrency = val.GetString() ?? "CHF"; - // Read datacube from the Analysis node's embedded content - var analysisNode = await meshQuery.QueryAsync($"path:{address}", ct: ct).FirstOrDefaultAsync(ct); - var rows = ParseDatacubeFromContent(analysisNode, businessUnit); - - return (rows, buCurrency); + var stream = await contentService.GetContentAsync("attachments", "datacube.csv", ct); + if (stream == null) + return (new List(), buCurrency); + using var reader = new StreamReader(stream); + var content = await reader.ReadToEndAsync(ct); + return (ParseLocalCsvContent(content, businessUnit), buCurrency); }).CombineLatest( LoadLocalLinesOfBusiness(workspace), - (result, lobs) => + (csvResult, lobs) => { var lobLookup = lobs.ToDictionary(l => l.SystemName, l => l.DisplayName); - return result.Rows.Select(row => row with + return csvResult.Rows.Select(row => row with { LineOfBusinessName = lobLookup.GetValueOrDefault(row.LineOfBusiness, row.LineOfBusiness), LocalLineOfBusinessName = lobLookup.GetValueOrDefault(row.LocalLineOfBusiness, row.LocalLineOfBusiness), - Currency = result.Currency + Currency = csvResult.Currency }).AsEnumerable(); } ).DistinctUntilChanged(); } /// - /// Parses datacube rows from a MeshNode's embedded content. - /// Handles both typed AnalysisContent and raw JsonElement content. + /// Parses local CSV content into FutuReDataCube rows. + /// Local CSV columns: Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual /// - internal static List ParseDatacubeFromContent(MeshNode? node, string businessUnit) + private static List ParseLocalCsvContent(string content, string businessUnit) { - if (node?.Content is AnalysisContent content && content.Datacube != null) - { - return content.Datacube.Select(row => new FutuReDataCube - { - Id = $"{row.Month}-{row.LineOfBusiness}-{row.AmountType}-{businessUnit}", - Month = row.Month, - Quarter = row.Quarter, - Year = row.Year, - LineOfBusiness = row.LineOfBusiness, - LocalLineOfBusiness = row.LineOfBusiness, - AmountType = row.AmountType, - BusinessUnit = businessUnit, - Estimate = row.Estimate, - Actual = row.Actual - }).ToList(); - } + var rows = new List(); + var lines = content.Split('\n'); - if (node?.Content is JsonElement json - && json.TryGetProperty("datacube", out var datacubeJson) - && datacubeJson.ValueKind == JsonValueKind.Array) + foreach (var rawLine in lines.Skip(1)) { - var rows = new List(); - foreach (var item in datacubeJson.EnumerateArray()) + var line = rawLine.TrimEnd('\r'); + if (string.IsNullOrWhiteSpace(line)) continue; + var parts = SplitCsvLine(line); + if (parts.Length < 6) continue; + + var month = parts[0]; + var lineOfBusiness = parts[3]; + var amountType = parts[4]; + + rows.Add(new FutuReDataCube { - var month = GetString(item, "month") ?? ""; - var lob = GetString(item, "lineOfBusiness") ?? ""; - var amountType = GetString(item, "amountType") ?? ""; - rows.Add(new FutuReDataCube - { - Id = $"{month}-{lob}-{amountType}-{businessUnit}", - Month = month, - Quarter = GetString(item, "quarter") ?? "", - Year = GetInt(item, "year"), - LineOfBusiness = lob, - LocalLineOfBusiness = lob, - AmountType = amountType, - BusinessUnit = businessUnit, - Estimate = GetDouble(item, "estimate"), - Actual = item.TryGetProperty("actual", out var actualVal) - && actualVal.ValueKind == JsonValueKind.Number - ? actualVal.GetDouble() - : null - }); - } - return rows; + Id = $"{month}-{lineOfBusiness}-{amountType}-{businessUnit}", + Month = month, + Quarter = parts[1], + Year = int.Parse(parts[2], CultureInfo.InvariantCulture), + LineOfBusiness = lineOfBusiness, + LocalLineOfBusiness = lineOfBusiness, + AmountType = amountType, + BusinessUnit = businessUnit, + Estimate = double.Parse(parts[5], CultureInfo.InvariantCulture), + Actual = parts.Length > 6 && !string.IsNullOrWhiteSpace(parts[6]) + ? double.Parse(parts[6], CultureInfo.InvariantCulture) + : null + }); } - return new List(); + return rows; } // --------------------------------------------------------------- @@ -195,15 +183,36 @@ public static IEnumerable AggregateToGroupLevel( LineOfBusinessName = lobLookup.GetValueOrDefault( rule.GroupLineOfBusiness, rule.GroupLineOfBusiness), Currency = currency, - // Percentages are stored as whole numbers (e.g. 80 = 80%); divide by 100. - Estimate = row.Estimate * (rule.Percentage / 100.0) * estimateFxRate, + Estimate = row.Estimate * rule.Percentage * estimateFxRate, Actual = row.Actual.HasValue - ? row.Actual.Value * (rule.Percentage / 100.0) * actualFxRate + ? row.Actual.Value * rule.Percentage * actualFxRate : null }); }); } + private static string[] SplitCsvLine(string line) + { + var parts = new List(); + var current = new System.Text.StringBuilder(); + bool inQuotes = false; + + foreach (char c in line) + { + if (c == '"') + inQuotes = !inQuotes; + else if (c == ',' && !inQuotes) + { + parts.Add(current.ToString()); + current.Clear(); + } + else + current.Append(c); + } + parts.Add(current.ToString()); + return parts.ToArray(); + } + // --------------------------------------------------------------- // Local LoB Loading (from BU namespace) // --------------------------------------------------------------- @@ -221,15 +230,15 @@ public static IObservable> LoadLocalLinesOfBusiness( : segments[0]; var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - // Use AccumulateChanges (not raw .Select) so incremental add/update/remove - // deltas are merged into the full collection instead of replacing it. - return AccumulateChanges( - meshQuery.ObserveQuery( + return meshQuery + .ObserveQuery( MeshQueryRequest.FromQuery( - $"nodeType:FutuRe/LineOfBusiness namespace:{buNamespace}/LineOfBusiness state:Active")), - ConvertToLineOfBusiness, - lob => lob.SystemName) - .Select(lobs => lobs.OrderBy(lob => lob.Order)); + $"nodeType:FutuRe/LineOfBusiness namespace:{buNamespace}/LineOfBusiness state:Active")) + .Select(change => change.Items + .Select(ConvertToLineOfBusiness) + .Where(lob => lob != null) + .Cast() + .OrderBy(lob => lob.Order)); } // --------------------------------------------------------------- @@ -242,12 +251,14 @@ public static IObservable> LoadLocalLinesOfBusiness( public static IObservable> LoadAmountTypes(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return AccumulateChanges( - meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/AmountType namespace:FutuRe/AmountType state:Active")), - ConvertToAmountType, - a => a.SystemName) - .Select(items => items.OrderBy(a => a.Order)); + return meshQuery + .ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/AmountType namespace:FutuRe/AmountType state:Active")) + .Select(change => change.Items + .Select(ConvertToAmountType) + .Where(a => a != null) + .Cast() + .OrderBy(a => a.Order)); } /// @@ -256,12 +267,14 @@ public static IObservable> LoadAmountTypes(IWorkspace wo public static IObservable> LoadCurrencies(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return AccumulateChanges( - meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/Currency namespace:FutuRe/Currency state:Active")), - ConvertToCurrency, - c => c.Id) - .Select(items => items.OrderBy(c => c.Order)); + return meshQuery + .ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/Currency namespace:FutuRe/Currency state:Active")) + .Select(change => change.Items + .Select(ConvertToCurrency) + .Where(c => c != null) + .Cast() + .OrderBy(c => c.Order)); } /// @@ -270,12 +283,14 @@ public static IObservable> LoadCurrencies(IWorkspace works public static IObservable> LoadCountries(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return AccumulateChanges( - meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/Country namespace:FutuRe/Country state:Active")), - ConvertToCountry, - c => c.Id) - .Select(items => items.OrderBy(c => c.Order)); + return meshQuery + .ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/Country namespace:FutuRe/Country state:Active")) + .Select(change => change.Items + .Select(ConvertToCountry) + .Where(c => c != null) + .Cast() + .OrderBy(c => c.Order)); } /// @@ -285,11 +300,13 @@ public static IObservable> LoadTransactionMappin { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return AccumulateChanges( - meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/TransactionMapping namespace:FutuRe scope:descendants")), - ConvertToTransactionMapping, - m => m.Id); + return meshQuery + .ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/TransactionMapping namespace:FutuRe scope:descendants")) + .Select(change => change.Items + .Select(ConvertToTransactionMapping) + .Where(m => m != null) + .Cast()); } /// @@ -298,12 +315,14 @@ public static IObservable> LoadTransactionMappin public static IObservable> LoadExchangeRates(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return AccumulateChanges( - meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/ExchangeRate namespace:FutuRe/ExchangeRate state:Active")), - ConvertToExchangeRate, - fx => fx.SystemName) - .Select(items => items.OrderBy(fx => fx.Order)); + return meshQuery + .ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/ExchangeRate namespace:FutuRe/ExchangeRate state:Active")) + .Select(change => change.Items + .Select(ConvertToExchangeRate) + .Where(fx => fx != null) + .Cast() + .OrderBy(fx => fx.Order)); } /// @@ -312,11 +331,13 @@ public static IObservable> LoadExchangeRates(IWorkspac public static IObservable> LoadBusinessUnits(IWorkspace workspace) { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return AccumulateChanges( - meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/BusinessUnit namespace:FutuRe state:Active")), - ConvertToBusinessUnit, - bu => bu.Id); + return meshQuery + .ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/BusinessUnit namespace:FutuRe state:Active")) + .Select(change => change.Items + .Select(ConvertToBusinessUnit) + .Where(bu => bu != null) + .Cast()); } /// @@ -326,12 +347,14 @@ public static IObservable> LoadLinesOfBusinessFromNo { var meshQuery = workspace.Hub.ServiceProvider.GetRequiredService(); - return AccumulateChanges( - meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:FutuRe/LineOfBusiness namespace:FutuRe/LineOfBusiness state:Active")), - ConvertToLineOfBusiness, - lob => lob.SystemName) - .Select(lobs => lobs.OrderBy(lob => lob.Order)); + return meshQuery + .ObserveQuery( + MeshQueryRequest.FromQuery("nodeType:FutuRe/LineOfBusiness namespace:FutuRe/LineOfBusiness state:Active")) + .Select(change => change.Items + .Select(ConvertToLineOfBusiness) + .Where(lob => lob != null) + .Cast() + .OrderBy(lob => lob.Order)); } // --------------------------------------------------------------- @@ -485,48 +508,4 @@ private static bool GetBool(JsonElement json, string property) => json.TryGetProperty(property, out var val) && (val.ValueKind == JsonValueKind.True || val.ValueKind == JsonValueKind.False) && val.GetBoolean(); - - // --------------------------------------------------------------- - // Incremental Change Accumulation - // --------------------------------------------------------------- - - /// - /// Accumulates incremental ObserveQuery changes into a full collection. - /// Initial/Reset emissions replace the entire dictionary; Added/Updated/Removed - /// apply deltas on top of the current state. - /// This keeps charts reactive to single-field edits (e.g. a mapping percentage) - /// without losing the rest of the collection. - /// - private static IObservable> AccumulateChanges( - IObservable> source, - Func convert, - Func getKey) - where T : class - { - return source - .Scan( - ImmutableDictionary.Empty, - (current, change) => - { - if (change.ChangeType is QueryChangeType.Initial or QueryChangeType.Reset) - return change.Items - .Select(convert) - .Where(item => item != null) - .Cast() - .ToImmutableDictionary(getKey); - - var builder = current.ToBuilder(); - foreach (var node in change.Items) - { - var item = convert(node); - if (item == null) continue; - if (change.ChangeType == QueryChangeType.Removed) - builder.Remove(getKey(item)); - else // Added or Updated - builder[getKey(item)] = item; - } - return builder.ToImmutable(); - }) - .Select(dict => dict.Values.AsEnumerable()); - } } diff --git a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs index 2ba7920c9..b3399b94d 100644 --- a/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs +++ b/samples/Graph/Data/FutuRe/GroupAnalysis/_Source/ProfitabilityLayoutAreas.cs @@ -622,7 +622,7 @@ private static string BuildWaterfallSvg( var tickValue = maxValue * i / 4; var y = marginTop + ScaleY(tickValue); sb.AppendLine($" "); - sb.AppendLine($" {tickValue:N0}"); + sb.AppendLine($" {tickValue:F0}"); } // Bars, labels, and connectors diff --git a/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs b/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs index 264a1a688..57a90541c 100644 --- a/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs +++ b/samples/Graph/Data/FutuRe/LocalAnalysis/_Source/LocalAnalysisConfig.cs @@ -13,9 +13,6 @@ /// /// Configures a local business unit analysis hub: loads CSV data /// and enriches with local line of business display names. -/// Registers the same reference/mapping data sources used by group analysis -/// (exchange rates, business units, transaction mappings, lines of business) -/// so local views have access to all dimensions needed for profitability reporting. /// public static class LocalAnalysisConfig { @@ -25,17 +22,7 @@ public static MessageHubConfiguration ConfigureLocalAnalysis(this MessageHubConf .AddData(data => data .WithVirtualDataSource("ReferenceData", vs => vs .WithVirtualType( - workspace => FutuReDataLoader.LoadAmountTypes(workspace)) - .WithVirtualType( - workspace => FutuReDataLoader.LoadExchangeRates(workspace)) - .WithVirtualType( - workspace => FutuReDataLoader.LoadBusinessUnits(workspace))) - .WithVirtualDataSource("TransactionMapping", vs => vs - .WithVirtualType( - workspace => FutuReDataLoader.LoadTransactionMappingsFromNodes(workspace))) - .WithVirtualDataSource("LineOfBusiness", vs => vs - .WithVirtualType( - workspace => FutuReDataLoader.LoadLinesOfBusinessFromNodes(workspace))) + workspace => FutuReDataLoader.LoadAmountTypes(workspace))) .WithVirtualDataSource("LocalData", vs => vs .WithVirtualType( workspace => FutuReDataLoader.LoadLocalDataCube(workspace)))) diff --git a/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs b/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs index caca49016..3ad22a805 100644 --- a/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs +++ b/samples/Graph/Data/FutuRe/TransactionMapping/_Source/TransactionMapping.cs @@ -53,9 +53,9 @@ public record TransactionMapping public string GroupLineOfBusinessName { get; init; } = string.Empty; /// - /// Fraction of local LoB amount allocated to this group LoB (0..100). + /// Fraction of local LoB amount allocated to this group LoB (0..1). /// [Display(Name = "Percentage")] - [DisplayFormat(DataFormatString = "{0:0}%")] + [DisplayFormat(DataFormatString = "{0:P0}")] public double Percentage { get; init; } } diff --git a/samples/Graph/Data/FutuRe/WhyDataMesh.md b/samples/Graph/Data/FutuRe/WhyDataMesh.md index ece35abb0..fa232f10e 100644 --- a/samples/Graph/Data/FutuRe/WhyDataMesh.md +++ b/samples/Graph/Data/FutuRe/WhyDataMesh.md @@ -81,7 +81,7 @@ graph LR ## Data is Addressed, Not Copied -Data stays where it lives. Each BU's datacube is embedded in its own Analysis MeshNode — the same node that defines the hub, its layout areas, and its configuration. Consumers reference it by address — `@FutuRe/EuropeRe/Analysis` — zero copies, zero staleness, zero reconciliation. This works identically across all deployment modes (filesystem, PostgreSQL, Azure). +Data stays where it lives. Consumers reference it by address — `@FutuRe/EuropeRe/Analysis` — zero copies, zero staleness, zero reconciliation.
diff --git a/samples/Graph/Data/FutuRe/index.md b/samples/Graph/Data/FutuRe/index.md index f15cedf82..d23730c57 100644 --- a/samples/Graph/Data/FutuRe/index.md +++ b/samples/Graph/Data/FutuRe/index.md @@ -88,7 +88,9 @@ FutuRe has three business units across three continents. Each one grew independe Each BU writes business in its own currency (EUR, USD, JPY), classifies products with its own taxonomy, and reports on its own schedule. The group CFO wants one consolidated view. Today, that means weeks of reconciliation. -## Step 1: Local Data Cubes +--- + +# Step 1: Local Data Cubes Instead of ripping out existing systems, each BU creates a **local data product** — a structured data cube with its own Lines of Business, its own currency, and its own Performance. @@ -152,7 +154,9 @@ Each cube is a self-contained data product. The BU owns it, controls its quality - [EuropeRe Analysis Hub](@FutuRe/EuropeRe/Analysis/AnnualReport) — 8 local LoBs, EUR - [AmericasIns Analysis Hub](@FutuRe/AmericasIns/Analysis/AnnualReport) — 8 local LoBs, USD -## Step 2: Combining into a Group View +--- + +# Step 2: Combining into a Group View To consolidate, we need two transformations — and both are applied **virtually at query time**, with zero data copying. @@ -215,9 +219,11 @@ EuropeRe calls it "Household." AmericasIns calls it "Homeowners." Both map to th Three currencies, two conversion modes (Plan rate vs. Actuals rate), plus the option to view original currency. A single toolbar dropdown switches the entire dashboard — no recalculation, no spreadsheet exports. -- [Explore the FX Conversion story →](@FutuRe/FxConversion) +[Explore the FX Conversion story →](@FutuRe/FxConversion) -## Step 3: Onboarding AsiaRe +--- + +# Step 3: Onboarding AsiaRe When FutuRe acquires AsiaRe, the new unit needs to map its local product lines to the group standard. Traditionally a multi-month spreadsheet exercise — here, a MeshWeaver agent reads an email discussion between actuaries, proposes structured mapping rules, and integrates AsiaRe into the group Performance. @@ -241,7 +247,7 @@ graph LR Onboarding drops from months to minutes. The resulting rules are versioned, auditable, and governed — not buried in a spreadsheet. -- [See the AsiaRe onboarding thread →](@FutuRe/AsiaRe/TransactionMapping/MappingRules/_Thread/t1) +[See the AsiaRe onboarding thread →](@FutuRe/AsiaRe/TransactionMapping/MappingRules/_Thread/t1) --- @@ -249,17 +255,15 @@ Onboarding drops from months to minutes. The resulting rules are versioned, audi The group profitability dashboard assembles data from all business units in real time. Switch currencies, drill into Lines of Business, compare Plan vs. Actuals — all from one view. -- [Access the group profitability annual report dashboard →](@FutuRe/Analysis/AnnualReport) +@("FutuRe/Analysis/AnnualReport") --- # Data Where It Belongs -No ETL pipelines. No nightly batch jobs. No stale copies. Each BU owns its data — embedded directly in its Analysis MeshNode. The group view is assembled virtually through reactive stream composition. When EuropeRe updates a number, the group dashboard updates instantly. - -This architecture is deployment-mode independent: the same data flows work whether running as a standalone monolith on the filesystem, with PostgreSQL in local development, or distributed across Azure Container Apps. BU data ownership is preserved at every level. +No ETL pipelines. No nightly batch jobs. No stale copies. Each BU owns its data. The group view is assembled virtually through reactive stream composition. When EuropeRe updates a number, the group dashboard updates instantly. -- [How virtual data distribution works →](@FutuRe/DataDistribution) +[How virtual data distribution works →](@FutuRe/DataDistribution) --- @@ -267,8 +271,8 @@ This architecture is deployment-mode independent: the same data flows work wheth Every mapping rule, every exchange rate, every data product comes with clear ownership, SLOs, and audit trails. -- [Group Lines of Business →](@FutuRe/LineOfBusiness/Search) — the 10 standard categories with SLOs -- [Exchange Rates →](@FutuRe/ExchangeRate) — 4 currency pairs with governance -- [EuropeRe Mapping Rules →](@FutuRe/EuropeRe/TransactionMapping/MappingRules) — 13 split rules across 8 local LoBs -- [AmericasIns Mapping Rules →](@FutuRe/AmericasIns/TransactionMapping/MappingRules) — 14 split rules across 8 local LoBs -- [Why Data Mesh? →](@FutuRe/WhyDataMesh) — The principles behind this architecture +- [Group Lines of Business](@FutuRe/LineOfBusiness/Search) — the 10 standard categories with SLOs +- [Exchange Rates](@FutuRe/ExchangeRate) — 4 currency pairs with governance +- [EuropeRe Mapping Rules](@FutuRe/EuropeRe/TransactionMapping/MappingRules) — 13 split rules across 8 local LoBs +- [AmericasIns Mapping Rules](@FutuRe/AmericasIns/TransactionMapping/MappingRules) — 14 split rules across 8 local LoBs +- [Why Data Mesh?](@FutuRe/WhyDataMesh) — The principles behind this architecture diff --git a/samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv b/samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv new file mode 100644 index 000000000..6dd339e4e --- /dev/null +++ b/samples/Graph/attachments/FutuRe/AmericasIns/Analysis/datacube.csv @@ -0,0 +1,865 @@ +Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual +2024-09,Q3-2024,2024,AGRICULTURE,CapitalCost,770000, +2024-09,Q3-2024,2024,AGRICULTURE,Claims,10885000,11102700 +2024-09,Q3-2024,2024,AGRICULTURE,ExpectedProfit,700000, +2024-09,Q3-2024,2024,AGRICULTURE,ExternalCost,1400000,1428000 +2024-09,Q3-2024,2024,AGRICULTURE,InternalCost,1680000, +2024-09,Q3-2024,2024,AGRICULTURE,Premium,14000000,14280000 +2024-09,Q3-2024,2024,COMMERCIAL,CapitalCost,2640000, +2024-09,Q3-2024,2024,COMMERCIAL,Claims,32342613,32989465 +2024-09,Q3-2024,2024,COMMERCIAL,ExpectedProfit,2400000, +2024-09,Q3-2024,2024,COMMERCIAL,ExternalCost,4800000,4896000 +2024-09,Q3-2024,2024,COMMERCIAL,InternalCost,5760000, +2024-09,Q3-2024,2024,COMMERCIAL,Premium,48000000,48960000 +2024-09,Q3-2024,2024,CYBER_TECH,CapitalCost,550000, +2024-09,Q3-2024,2024,CYBER_TECH,Claims,4656000,4749120 +2024-09,Q3-2024,2024,CYBER_TECH,ExpectedProfit,500000, +2024-09,Q3-2024,2024,CYBER_TECH,ExternalCost,1000000,1020000 +2024-09,Q3-2024,2024,CYBER_TECH,InternalCost,1200000, +2024-09,Q3-2024,2024,CYBER_TECH,Premium,10000000,10200000 +2024-09,Q3-2024,2024,ENERGY_MINING,CapitalCost,1815000, +2024-09,Q3-2024,2024,ENERGY_MINING,Claims,23031067,23491688 +2024-09,Q3-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, +2024-09,Q3-2024,2024,ENERGY_MINING,ExternalCost,3300000,3366000 +2024-09,Q3-2024,2024,ENERGY_MINING,InternalCost,3960000, +2024-09,Q3-2024,2024,ENERGY_MINING,Premium,33000000,33660000 +2024-09,Q3-2024,2024,HOMEOWNERS,CapitalCost,3410000, +2024-09,Q3-2024,2024,HOMEOWNERS,Claims,51605987,52638107 +2024-09,Q3-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, +2024-09,Q3-2024,2024,HOMEOWNERS,ExternalCost,6200000,6324000 +2024-09,Q3-2024,2024,HOMEOWNERS,InternalCost,7440000, +2024-09,Q3-2024,2024,HOMEOWNERS,Premium,65720000,67034400 +2024-09,Q3-2024,2024,LIFE_ANN,CapitalCost,2090000, +2024-09,Q3-2024,2024,LIFE_ANN,Claims,20900000,21318000 +2024-09,Q3-2024,2024,LIFE_ANN,ExpectedProfit,1900000, +2024-09,Q3-2024,2024,LIFE_ANN,ExternalCost,3800000,3876000 +2024-09,Q3-2024,2024,LIFE_ANN,InternalCost,4560000, +2024-09,Q3-2024,2024,LIFE_ANN,Premium,38000000,38760000 +2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, +2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,11566800 +2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1836000 +2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, +2024-09,Q3-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,18360000 +2024-09,Q3-2024,2024,WORKERS_COMP,CapitalCost,2310000, +2024-09,Q3-2024,2024,WORKERS_COMP,Claims,26493600,27023472 +2024-09,Q3-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, +2024-09,Q3-2024,2024,WORKERS_COMP,ExternalCost,4200000,4284000 +2024-09,Q3-2024,2024,WORKERS_COMP,InternalCost,5040000, +2024-09,Q3-2024,2024,WORKERS_COMP,Premium,42000000,42840000 +2024-10,Q4-2024,2024,AGRICULTURE,CapitalCost,770000, +2024-10,Q4-2024,2024,AGRICULTURE,Claims,9902200,9605134 +2024-10,Q4-2024,2024,AGRICULTURE,ExpectedProfit,700000, +2024-10,Q4-2024,2024,AGRICULTURE,ExternalCost,1400000,1358000 +2024-10,Q4-2024,2024,AGRICULTURE,InternalCost,1680000, +2024-10,Q4-2024,2024,AGRICULTURE,Premium,14000000,13580000 +2024-10,Q4-2024,2024,COMMERCIAL,CapitalCost,2640000, +2024-10,Q4-2024,2024,COMMERCIAL,Claims,31113813,30180399 +2024-10,Q4-2024,2024,COMMERCIAL,ExpectedProfit,2400000, +2024-10,Q4-2024,2024,COMMERCIAL,ExternalCost,4800000,4656000 +2024-10,Q4-2024,2024,COMMERCIAL,InternalCost,5760000, +2024-10,Q4-2024,2024,COMMERCIAL,Premium,48000000,46560000 +2024-10,Q4-2024,2024,CYBER_TECH,CapitalCost,550000, +2024-10,Q4-2024,2024,CYBER_TECH,Claims,5136000,4981920 +2024-10,Q4-2024,2024,CYBER_TECH,ExpectedProfit,500000, +2024-10,Q4-2024,2024,CYBER_TECH,ExternalCost,1000000,970000 +2024-10,Q4-2024,2024,CYBER_TECH,InternalCost,1200000, +2024-10,Q4-2024,2024,CYBER_TECH,Premium,10000000,9700000 +2024-10,Q4-2024,2024,ENERGY_MINING,CapitalCost,1815000, +2024-10,Q4-2024,2024,ENERGY_MINING,Claims,21183067,20547575 +2024-10,Q4-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, +2024-10,Q4-2024,2024,ENERGY_MINING,ExternalCost,3300000,3201000 +2024-10,Q4-2024,2024,ENERGY_MINING,InternalCost,3960000, +2024-10,Q4-2024,2024,ENERGY_MINING,Premium,33000000,32010000 +2024-10,Q4-2024,2024,HOMEOWNERS,CapitalCost,3410000, +2024-10,Q4-2024,2024,HOMEOWNERS,Claims,48360101,46909298 +2024-10,Q4-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, +2024-10,Q4-2024,2024,HOMEOWNERS,ExternalCost,6200000,6014000 +2024-10,Q4-2024,2024,HOMEOWNERS,InternalCost,7440000, +2024-10,Q4-2024,2024,HOMEOWNERS,Premium,63240000,61342800 +2024-10,Q4-2024,2024,LIFE_ANN,CapitalCost,2090000, +2024-10,Q4-2024,2024,LIFE_ANN,Claims,20900000,20273000 +2024-10,Q4-2024,2024,LIFE_ANN,ExpectedProfit,1900000, +2024-10,Q4-2024,2024,LIFE_ANN,ExternalCost,3800000,3686000 +2024-10,Q4-2024,2024,LIFE_ANN,InternalCost,4560000, +2024-10,Q4-2024,2024,LIFE_ANN,Premium,38000000,36860000 +2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, +2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,10999800 +2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1746000 +2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, +2024-10,Q4-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,17460000 +2024-10,Q4-2024,2024,WORKERS_COMP,CapitalCost,2310000, +2024-10,Q4-2024,2024,WORKERS_COMP,Claims,25384800,24623256 +2024-10,Q4-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, +2024-10,Q4-2024,2024,WORKERS_COMP,ExternalCost,4200000,4074000 +2024-10,Q4-2024,2024,WORKERS_COMP,InternalCost,5040000, +2024-10,Q4-2024,2024,WORKERS_COMP,Premium,42000000,40740000 +2024-11,Q4-2024,2024,AGRICULTURE,CapitalCost,770000, +2024-11,Q4-2024,2024,AGRICULTURE,Claims,8919400,9365370 +2024-11,Q4-2024,2024,AGRICULTURE,ExpectedProfit,700000, +2024-11,Q4-2024,2024,AGRICULTURE,ExternalCost,1400000,1470000 +2024-11,Q4-2024,2024,AGRICULTURE,InternalCost,1680000, +2024-11,Q4-2024,2024,AGRICULTURE,Premium,14000000,14700000 +2024-11,Q4-2024,2024,COMMERCIAL,CapitalCost,2640000, +2024-11,Q4-2024,2024,COMMERCIAL,Claims,29885013,31379264 +2024-11,Q4-2024,2024,COMMERCIAL,ExpectedProfit,2400000, +2024-11,Q4-2024,2024,COMMERCIAL,ExternalCost,4800000,5040000 +2024-11,Q4-2024,2024,COMMERCIAL,InternalCost,5760000, +2024-11,Q4-2024,2024,COMMERCIAL,Premium,48000000,50400000 +2024-11,Q4-2024,2024,CYBER_TECH,CapitalCost,550000, +2024-11,Q4-2024,2024,CYBER_TECH,Claims,5424000,5695200 +2024-11,Q4-2024,2024,CYBER_TECH,ExpectedProfit,500000, +2024-11,Q4-2024,2024,CYBER_TECH,ExternalCost,1000000,1050000 +2024-11,Q4-2024,2024,CYBER_TECH,InternalCost,1200000, +2024-11,Q4-2024,2024,CYBER_TECH,Premium,10000000,10500000 +2024-11,Q4-2024,2024,ENERGY_MINING,CapitalCost,1815000, +2024-11,Q4-2024,2024,ENERGY_MINING,Claims,20443867,21466060 +2024-11,Q4-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, +2024-11,Q4-2024,2024,ENERGY_MINING,ExternalCost,3300000,3465000 +2024-11,Q4-2024,2024,ENERGY_MINING,InternalCost,3960000, +2024-11,Q4-2024,2024,ENERGY_MINING,Premium,33000000,34650000 +2024-11,Q4-2024,2024,HOMEOWNERS,CapitalCost,3410000, +2024-11,Q4-2024,2024,HOMEOWNERS,Claims,41991600,44091180 +2024-11,Q4-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, +2024-11,Q4-2024,2024,HOMEOWNERS,ExternalCost,6200000,6510000 +2024-11,Q4-2024,2024,HOMEOWNERS,InternalCost,7440000, +2024-11,Q4-2024,2024,HOMEOWNERS,Premium,58900000,61845000 +2024-11,Q4-2024,2024,LIFE_ANN,CapitalCost,2090000, +2024-11,Q4-2024,2024,LIFE_ANN,Claims,20900000,21945000 +2024-11,Q4-2024,2024,LIFE_ANN,ExpectedProfit,1900000, +2024-11,Q4-2024,2024,LIFE_ANN,ExternalCost,3800000,3990000 +2024-11,Q4-2024,2024,LIFE_ANN,InternalCost,4560000, +2024-11,Q4-2024,2024,LIFE_ANN,Premium,38000000,39900000 +2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, +2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,11907000 +2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1890000 +2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, +2024-11,Q4-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,18900000 +2024-11,Q4-2024,2024,WORKERS_COMP,CapitalCost,2310000, +2024-11,Q4-2024,2024,WORKERS_COMP,Claims,23610720,24791256 +2024-11,Q4-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, +2024-11,Q4-2024,2024,WORKERS_COMP,ExternalCost,4200000,4410000 +2024-11,Q4-2024,2024,WORKERS_COMP,InternalCost,5040000, +2024-11,Q4-2024,2024,WORKERS_COMP,Premium,42000000,44100000 +2024-12,Q4-2024,2024,AGRICULTURE,CapitalCost,770000, +2024-12,Q4-2024,2024,AGRICULTURE,Claims,7936600,7777868 +2024-12,Q4-2024,2024,AGRICULTURE,ExpectedProfit,700000, +2024-12,Q4-2024,2024,AGRICULTURE,ExternalCost,1400000,1372000 +2024-12,Q4-2024,2024,AGRICULTURE,InternalCost,1680000, +2024-12,Q4-2024,2024,AGRICULTURE,Premium,14000000,13720000 +2024-12,Q4-2024,2024,COMMERCIAL,CapitalCost,2640000, +2024-12,Q4-2024,2024,COMMERCIAL,Claims,29393493,28805623 +2024-12,Q4-2024,2024,COMMERCIAL,ExpectedProfit,2400000, +2024-12,Q4-2024,2024,COMMERCIAL,ExternalCost,4800000,4704000 +2024-12,Q4-2024,2024,COMMERCIAL,InternalCost,5760000, +2024-12,Q4-2024,2024,COMMERCIAL,Premium,48000000,47040000 +2024-12,Q4-2024,2024,CYBER_TECH,CapitalCost,550000, +2024-12,Q4-2024,2024,CYBER_TECH,Claims,5904000,5785920 +2024-12,Q4-2024,2024,CYBER_TECH,ExpectedProfit,500000, +2024-12,Q4-2024,2024,CYBER_TECH,ExternalCost,1000000,980000 +2024-12,Q4-2024,2024,CYBER_TECH,InternalCost,1200000, +2024-12,Q4-2024,2024,CYBER_TECH,Premium,10000000,9800000 +2024-12,Q4-2024,2024,ENERGY_MINING,CapitalCost,1815000, +2024-12,Q4-2024,2024,ENERGY_MINING,Claims,21737467,21302718 +2024-12,Q4-2024,2024,ENERGY_MINING,ExpectedProfit,1650000, +2024-12,Q4-2024,2024,ENERGY_MINING,ExternalCost,3300000,3234000 +2024-12,Q4-2024,2024,ENERGY_MINING,InternalCost,3960000, +2024-12,Q4-2024,2024,ENERGY_MINING,Premium,33000000,32340000 +2024-12,Q4-2024,2024,HOMEOWNERS,CapitalCost,3410000, +2024-12,Q4-2024,2024,HOMEOWNERS,Claims,40578139,39766576 +2024-12,Q4-2024,2024,HOMEOWNERS,ExpectedProfit,3100000, +2024-12,Q4-2024,2024,HOMEOWNERS,ExternalCost,6200000,6076000 +2024-12,Q4-2024,2024,HOMEOWNERS,InternalCost,7440000, +2024-12,Q4-2024,2024,HOMEOWNERS,Premium,54560000,53468800 +2024-12,Q4-2024,2024,LIFE_ANN,CapitalCost,2090000, +2024-12,Q4-2024,2024,LIFE_ANN,Claims,20900000,20482000 +2024-12,Q4-2024,2024,LIFE_ANN,ExpectedProfit,1900000, +2024-12,Q4-2024,2024,LIFE_ANN,ExternalCost,3800000,3724000 +2024-12,Q4-2024,2024,LIFE_ANN,InternalCost,4560000, +2024-12,Q4-2024,2024,LIFE_ANN,Premium,38000000,37240000 +2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,CapitalCost,990000, +2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,Claims,11340000,11113200 +2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,ExternalCost,1800000,1764000 +2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,InternalCost,2160000, +2024-12,Q4-2024,2024,SPECIALTY_AVTN_US,Premium,18000000,17640000 +2024-12,Q4-2024,2024,WORKERS_COMP,CapitalCost,2310000, +2024-12,Q4-2024,2024,WORKERS_COMP,Claims,22723680,22269206 +2024-12,Q4-2024,2024,WORKERS_COMP,ExpectedProfit,2100000, +2024-12,Q4-2024,2024,WORKERS_COMP,ExternalCost,4200000,4116000 +2024-12,Q4-2024,2024,WORKERS_COMP,InternalCost,5040000, +2024-12,Q4-2024,2024,WORKERS_COMP,Premium,42000000,41160000 +2025-01,Q1-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-01,Q1-2025,2025,AGRICULTURE,Claims,7936600,8015966 +2025-01,Q1-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-01,Q1-2025,2025,AGRICULTURE,ExternalCost,1400000,1414000 +2025-01,Q1-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-01,Q1-2025,2025,AGRICULTURE,Premium,14000000,14140000 +2025-01,Q1-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-01,Q1-2025,2025,COMMERCIAL,Claims,31113813,31424951 +2025-01,Q1-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-01,Q1-2025,2025,COMMERCIAL,ExternalCost,4800000,4848000 +2025-01,Q1-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-01,Q1-2025,2025,COMMERCIAL,Premium,48000000,48480000 +2025-01,Q1-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-01,Q1-2025,2025,CYBER_TECH,Claims,5424000,5478240 +2025-01,Q1-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-01,Q1-2025,2025,CYBER_TECH,ExternalCost,1000000,1010000 +2025-01,Q1-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-01,Q1-2025,2025,CYBER_TECH,Premium,10000000,10100000 +2025-01,Q1-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-01,Q1-2025,2025,ENERGY_MINING,Claims,22291867,22514786 +2025-01,Q1-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-01,Q1-2025,2025,ENERGY_MINING,ExternalCost,3300000,3333000 +2025-01,Q1-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-01,Q1-2025,2025,ENERGY_MINING,Premium,33000000,33330000 +2025-01,Q1-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-01,Q1-2025,2025,HOMEOWNERS,Claims,41745056,42162507 +2025-01,Q1-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-01,Q1-2025,2025,HOMEOWNERS,ExternalCost,6200000,6262000 +2025-01,Q1-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-01,Q1-2025,2025,HOMEOWNERS,Premium,57660000,58236600 +2025-01,Q1-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-01,Q1-2025,2025,LIFE_ANN,Claims,20900000,21109000 +2025-01,Q1-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-01,Q1-2025,2025,LIFE_ANN,ExternalCost,3800000,3838000 +2025-01,Q1-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-01,Q1-2025,2025,LIFE_ANN,Premium,38000000,38380000 +2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11453400 +2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1818000 +2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-01,Q1-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18180000 +2025-01,Q1-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-01,Q1-2025,2025,WORKERS_COMP,Claims,24276000,24518760 +2025-01,Q1-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-01,Q1-2025,2025,WORKERS_COMP,ExternalCost,4200000,4242000 +2025-01,Q1-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-01,Q1-2025,2025,WORKERS_COMP,Premium,42000000,42420000 +2025-02,Q1-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-02,Q1-2025,2025,AGRICULTURE,Claims,8264200,7933632 +2025-02,Q1-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-02,Q1-2025,2025,AGRICULTURE,ExternalCost,1400000,1344000 +2025-02,Q1-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-02,Q1-2025,2025,AGRICULTURE,Premium,14000000,13440000 +2025-02,Q1-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-02,Q1-2025,2025,COMMERCIAL,Claims,29885013,28689612 +2025-02,Q1-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-02,Q1-2025,2025,COMMERCIAL,ExternalCost,4800000,4608000 +2025-02,Q1-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-02,Q1-2025,2025,COMMERCIAL,Premium,48000000,46080000 +2025-02,Q1-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-02,Q1-2025,2025,CYBER_TECH,Claims,4944000,4746240 +2025-02,Q1-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-02,Q1-2025,2025,CYBER_TECH,ExternalCost,1000000,960000 +2025-02,Q1-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-02,Q1-2025,2025,CYBER_TECH,Premium,10000000,9600000 +2025-02,Q1-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-02,Q1-2025,2025,ENERGY_MINING,Claims,21183067,20335744 +2025-02,Q1-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-02,Q1-2025,2025,ENERGY_MINING,ExternalCost,3300000,3168000 +2025-02,Q1-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-02,Q1-2025,2025,ENERGY_MINING,Premium,33000000,31680000 +2025-02,Q1-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-02,Q1-2025,2025,HOMEOWNERS,Claims,39998842,38398888 +2025-02,Q1-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-02,Q1-2025,2025,HOMEOWNERS,ExternalCost,6200000,5952000 +2025-02,Q1-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-02,Q1-2025,2025,HOMEOWNERS,Premium,55800000,53568000 +2025-02,Q1-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-02,Q1-2025,2025,LIFE_ANN,Claims,20900000,20064000 +2025-02,Q1-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-02,Q1-2025,2025,LIFE_ANN,ExternalCost,3800000,3648000 +2025-02,Q1-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-02,Q1-2025,2025,LIFE_ANN,Premium,38000000,36480000 +2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,10886400 +2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1728000 +2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-02,Q1-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17280000 +2025-02,Q1-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-02,Q1-2025,2025,WORKERS_COMP,Claims,23167200,22240512 +2025-02,Q1-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-02,Q1-2025,2025,WORKERS_COMP,ExternalCost,4200000,4032000 +2025-02,Q1-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-02,Q1-2025,2025,WORKERS_COMP,Premium,42000000,40320000 +2025-03,Q1-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-03,Q1-2025,2025,AGRICULTURE,Claims,8919400,9186982 +2025-03,Q1-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-03,Q1-2025,2025,AGRICULTURE,ExternalCost,1400000,1442000 +2025-03,Q1-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-03,Q1-2025,2025,AGRICULTURE,Premium,14000000,14420000 +2025-03,Q1-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-03,Q1-2025,2025,COMMERCIAL,Claims,28656213,29515899 +2025-03,Q1-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-03,Q1-2025,2025,COMMERCIAL,ExternalCost,4800000,4944000 +2025-03,Q1-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-03,Q1-2025,2025,COMMERCIAL,Premium,48000000,49440000 +2025-03,Q1-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-03,Q1-2025,2025,CYBER_TECH,Claims,4464000,4597920 +2025-03,Q1-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-03,Q1-2025,2025,CYBER_TECH,ExternalCost,1000000,1030000 +2025-03,Q1-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-03,Q1-2025,2025,CYBER_TECH,Premium,10000000,10300000 +2025-03,Q1-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-03,Q1-2025,2025,ENERGY_MINING,Claims,19335067,19915119 +2025-03,Q1-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-03,Q1-2025,2025,ENERGY_MINING,ExternalCost,3300000,3399000 +2025-03,Q1-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-03,Q1-2025,2025,ENERGY_MINING,Premium,33000000,33990000 +2025-03,Q1-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-03,Q1-2025,2025,HOMEOWNERS,Claims,36855814,37961488 +2025-03,Q1-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-03,Q1-2025,2025,HOMEOWNERS,ExternalCost,6200000,6386000 +2025-03,Q1-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-03,Q1-2025,2025,HOMEOWNERS,Premium,60760000,62582800 +2025-03,Q1-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-03,Q1-2025,2025,LIFE_ANN,Claims,20900000,21527000 +2025-03,Q1-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-03,Q1-2025,2025,LIFE_ANN,ExternalCost,3800000,3914000 +2025-03,Q1-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-03,Q1-2025,2025,LIFE_ANN,Premium,38000000,39140000 +2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11680200 +2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1854000 +2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-03,Q1-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18540000 +2025-03,Q1-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-03,Q1-2025,2025,WORKERS_COMP,Claims,25384800,26146344 +2025-03,Q1-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-03,Q1-2025,2025,WORKERS_COMP,ExternalCost,4200000,4326000 +2025-03,Q1-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-03,Q1-2025,2025,WORKERS_COMP,Premium,42000000,43260000 +2025-04,Q2-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-04,Q2-2025,2025,AGRICULTURE,Claims,9574600,9478854 +2025-04,Q2-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-04,Q2-2025,2025,AGRICULTURE,ExternalCost,1400000,1386000 +2025-04,Q2-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-04,Q2-2025,2025,AGRICULTURE,Premium,14000000,13860000 +2025-04,Q2-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-04,Q2-2025,2025,COMMERCIAL,Claims,27427413,27153139 +2025-04,Q2-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-04,Q2-2025,2025,COMMERCIAL,ExternalCost,4800000,4752000 +2025-04,Q2-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-04,Q2-2025,2025,COMMERCIAL,Premium,48000000,47520000 +2025-04,Q2-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-04,Q2-2025,2025,CYBER_TECH,Claims,4176000,4134240 +2025-04,Q2-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-04,Q2-2025,2025,CYBER_TECH,ExternalCost,1000000,990000 +2025-04,Q2-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-04,Q2-2025,2025,CYBER_TECH,Premium,10000000,9900000 +2025-04,Q2-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-04,Q2-2025,2025,ENERGY_MINING,Claims,18595867,18409908 +2025-04,Q2-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-04,Q2-2025,2025,ENERGY_MINING,ExternalCost,3300000,3267000 +2025-04,Q2-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-04,Q2-2025,2025,ENERGY_MINING,Premium,33000000,32670000 +2025-04,Q2-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-04,Q2-2025,2025,HOMEOWNERS,Claims,35725957,35368697 +2025-04,Q2-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-04,Q2-2025,2025,HOMEOWNERS,ExternalCost,6200000,6138000 +2025-04,Q2-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-04,Q2-2025,2025,HOMEOWNERS,Premium,62000000,61380000 +2025-04,Q2-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-04,Q2-2025,2025,LIFE_ANN,Claims,20900000,20691000 +2025-04,Q2-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-04,Q2-2025,2025,LIFE_ANN,ExternalCost,3800000,3762000 +2025-04,Q2-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-04,Q2-2025,2025,LIFE_ANN,Premium,38000000,37620000 +2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11226600 +2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1782000 +2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-04,Q2-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17820000 +2025-04,Q2-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-04,Q2-2025,2025,WORKERS_COMP,Claims,26493600,26228664 +2025-04,Q2-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-04,Q2-2025,2025,WORKERS_COMP,ExternalCost,4200000,4158000 +2025-04,Q2-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-04,Q2-2025,2025,WORKERS_COMP,Premium,42000000,41580000 +2025-05,Q2-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-05,Q2-2025,2025,AGRICULTURE,Claims,10557400,10979696 +2025-05,Q2-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-05,Q2-2025,2025,AGRICULTURE,ExternalCost,1400000,1456000 +2025-05,Q2-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-05,Q2-2025,2025,AGRICULTURE,Premium,14000000,14560000 +2025-05,Q2-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-05,Q2-2025,2025,COMMERCIAL,Claims,27918933,29035690 +2025-05,Q2-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-05,Q2-2025,2025,COMMERCIAL,ExternalCost,4800000,4992000 +2025-05,Q2-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-05,Q2-2025,2025,COMMERCIAL,Premium,48000000,49920000 +2025-05,Q2-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-05,Q2-2025,2025,CYBER_TECH,Claims,4320000,4492800 +2025-05,Q2-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-05,Q2-2025,2025,CYBER_TECH,ExternalCost,1000000,1040000 +2025-05,Q2-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-05,Q2-2025,2025,CYBER_TECH,Premium,10000000,10400000 +2025-05,Q2-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-05,Q2-2025,2025,ENERGY_MINING,Claims,18965467,19724086 +2025-05,Q2-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-05,Q2-2025,2025,ENERGY_MINING,ExternalCost,3300000,3432000 +2025-05,Q2-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-05,Q2-2025,2025,ENERGY_MINING,Premium,33000000,34320000 +2025-05,Q2-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-05,Q2-2025,2025,HOMEOWNERS,Claims,37044884,38526679 +2025-05,Q2-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-05,Q2-2025,2025,HOMEOWNERS,ExternalCost,6200000,6448000 +2025-05,Q2-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-05,Q2-2025,2025,HOMEOWNERS,Premium,64480000,67059200 +2025-05,Q2-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-05,Q2-2025,2025,LIFE_ANN,Claims,20900000,21736000 +2025-05,Q2-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-05,Q2-2025,2025,LIFE_ANN,ExternalCost,3800000,3952000 +2025-05,Q2-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-05,Q2-2025,2025,LIFE_ANN,Premium,38000000,39520000 +2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11793600 +2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1872000 +2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-05,Q2-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18720000 +2025-05,Q2-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-05,Q2-2025,2025,WORKERS_COMP,Claims,27158880,28245235 +2025-05,Q2-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-05,Q2-2025,2025,WORKERS_COMP,ExternalCost,4200000,4368000 +2025-05,Q2-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-05,Q2-2025,2025,WORKERS_COMP,Premium,42000000,43680000 +2025-06,Q2-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-06,Q2-2025,2025,AGRICULTURE,Claims,11212600,10651970 +2025-06,Q2-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-06,Q2-2025,2025,AGRICULTURE,ExternalCost,1400000,1330000 +2025-06,Q2-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-06,Q2-2025,2025,AGRICULTURE,Premium,14000000,13300000 +2025-06,Q2-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-06,Q2-2025,2025,COMMERCIAL,Claims,29885013,28390762 +2025-06,Q2-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-06,Q2-2025,2025,COMMERCIAL,ExternalCost,4800000,4560000 +2025-06,Q2-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-06,Q2-2025,2025,COMMERCIAL,Premium,48000000,45600000 +2025-06,Q2-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-06,Q2-2025,2025,CYBER_TECH,Claims,4656000,4423200 +2025-06,Q2-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-06,Q2-2025,2025,CYBER_TECH,ExternalCost,1000000,950000 +2025-06,Q2-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-06,Q2-2025,2025,CYBER_TECH,Premium,10000000,9500000 +2025-06,Q2-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-06,Q2-2025,2025,ENERGY_MINING,Claims,22291867,21177274 +2025-06,Q2-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-06,Q2-2025,2025,ENERGY_MINING,ExternalCost,3300000,3135000 +2025-06,Q2-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-06,Q2-2025,2025,ENERGY_MINING,Premium,33000000,31350000 +2025-06,Q2-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-06,Q2-2025,2025,HOMEOWNERS,Claims,39464930,37491684 +2025-06,Q2-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-06,Q2-2025,2025,HOMEOWNERS,ExternalCost,6200000,5890000 +2025-06,Q2-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-06,Q2-2025,2025,HOMEOWNERS,Premium,66960000,63612000 +2025-06,Q2-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-06,Q2-2025,2025,LIFE_ANN,Claims,20900000,19855000 +2025-06,Q2-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-06,Q2-2025,2025,LIFE_ANN,ExternalCost,3800000,3610000 +2025-06,Q2-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-06,Q2-2025,2025,LIFE_ANN,Premium,38000000,36100000 +2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,10773000 +2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1710000 +2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-06,Q2-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17100000 +2025-06,Q2-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-06,Q2-2025,2025,WORKERS_COMP,Claims,27602400,26222280 +2025-06,Q2-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-06,Q2-2025,2025,WORKERS_COMP,ExternalCost,4200000,3990000 +2025-06,Q2-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-06,Q2-2025,2025,WORKERS_COMP,Premium,42000000,39900000 +2025-07,Q3-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-07,Q3-2025,2025,AGRICULTURE,Claims,11867800,12579868 +2025-07,Q3-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-07,Q3-2025,2025,AGRICULTURE,ExternalCost,1400000,1484000 +2025-07,Q3-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-07,Q3-2025,2025,AGRICULTURE,Premium,14000000,14840000 +2025-07,Q3-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-07,Q3-2025,2025,COMMERCIAL,Claims,31113813,32980642 +2025-07,Q3-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-07,Q3-2025,2025,COMMERCIAL,ExternalCost,4800000,5088000 +2025-07,Q3-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-07,Q3-2025,2025,COMMERCIAL,Premium,48000000,50880000 +2025-07,Q3-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-07,Q3-2025,2025,CYBER_TECH,Claims,4944000,5240640 +2025-07,Q3-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-07,Q3-2025,2025,CYBER_TECH,ExternalCost,1000000,1060000 +2025-07,Q3-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-07,Q3-2025,2025,CYBER_TECH,Premium,10000000,10600000 +2025-07,Q3-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-07,Q3-2025,2025,ENERGY_MINING,Claims,23031067,24412931 +2025-07,Q3-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-07,Q3-2025,2025,ENERGY_MINING,ExternalCost,3300000,3498000 +2025-07,Q3-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-07,Q3-2025,2025,ENERGY_MINING,Premium,33000000,34980000 +2025-07,Q3-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-07,Q3-2025,2025,HOMEOWNERS,Claims,44087216,46732449 +2025-07,Q3-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-07,Q3-2025,2025,HOMEOWNERS,ExternalCost,6200000,6572000 +2025-07,Q3-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-07,Q3-2025,2025,HOMEOWNERS,Premium,69440000,73606400 +2025-07,Q3-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-07,Q3-2025,2025,LIFE_ANN,Claims,20900000,22154000 +2025-07,Q3-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-07,Q3-2025,2025,LIFE_ANN,ExternalCost,3800000,4028000 +2025-07,Q3-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-07,Q3-2025,2025,LIFE_ANN,Premium,38000000,40280000 +2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,12020400 +2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1908000 +2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-07,Q3-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,19080000 +2025-07,Q3-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-07,Q3-2025,2025,WORKERS_COMP,Claims,28045920,29728675 +2025-07,Q3-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-07,Q3-2025,2025,WORKERS_COMP,ExternalCost,4200000,4452000 +2025-07,Q3-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-07,Q3-2025,2025,WORKERS_COMP,Premium,42000000,44520000 +2025-08,Q3-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-08,Q3-2025,2025,AGRICULTURE,Claims,11540200,11309396 +2025-08,Q3-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-08,Q3-2025,2025,AGRICULTURE,ExternalCost,1400000,1372000 +2025-08,Q3-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-08,Q3-2025,2025,AGRICULTURE,Premium,14000000,13720000 +2025-08,Q3-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-08,Q3-2025,2025,COMMERCIAL,Claims,31851093,31214071 +2025-08,Q3-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-08,Q3-2025,2025,COMMERCIAL,ExternalCost,4800000,4704000 +2025-08,Q3-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-08,Q3-2025,2025,COMMERCIAL,Premium,48000000,47040000 +2025-08,Q3-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-08,Q3-2025,2025,CYBER_TECH,Claims,4464000,4374720 +2025-08,Q3-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-08,Q3-2025,2025,CYBER_TECH,ExternalCost,1000000,980000 +2025-08,Q3-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-08,Q3-2025,2025,CYBER_TECH,Premium,10000000,9800000 +2025-08,Q3-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-08,Q3-2025,2025,ENERGY_MINING,Claims,24139867,23657070 +2025-08,Q3-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-08,Q3-2025,2025,ENERGY_MINING,ExternalCost,3300000,3234000 +2025-08,Q3-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-08,Q3-2025,2025,ENERGY_MINING,Premium,33000000,32340000 +2025-08,Q3-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-08,Q3-2025,2025,HOMEOWNERS,Claims,49346273,48359348 +2025-08,Q3-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-08,Q3-2025,2025,HOMEOWNERS,ExternalCost,6200000,6076000 +2025-08,Q3-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-08,Q3-2025,2025,HOMEOWNERS,Premium,68200000,66836000 +2025-08,Q3-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-08,Q3-2025,2025,LIFE_ANN,Claims,20900000,20482000 +2025-08,Q3-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-08,Q3-2025,2025,LIFE_ANN,ExternalCost,3800000,3724000 +2025-08,Q3-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-08,Q3-2025,2025,LIFE_ANN,Premium,38000000,37240000 +2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11113200 +2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1764000 +2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-08,Q3-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17640000 +2025-08,Q3-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-08,Q3-2025,2025,WORKERS_COMP,Claims,27602400,27050352 +2025-08,Q3-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-08,Q3-2025,2025,WORKERS_COMP,ExternalCost,4200000,4116000 +2025-08,Q3-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-08,Q3-2025,2025,WORKERS_COMP,Premium,42000000,41160000 +2025-09,Q3-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-09,Q3-2025,2025,AGRICULTURE,Claims,10885000,10993850 +2025-09,Q3-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-09,Q3-2025,2025,AGRICULTURE,ExternalCost,1400000,1414000 +2025-09,Q3-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-09,Q3-2025,2025,AGRICULTURE,Premium,14000000,14140000 +2025-09,Q3-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-09,Q3-2025,2025,COMMERCIAL,Claims,32342613,32666039 +2025-09,Q3-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-09,Q3-2025,2025,COMMERCIAL,ExternalCost,4800000,4848000 +2025-09,Q3-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-09,Q3-2025,2025,COMMERCIAL,Premium,48000000,48480000 +2025-09,Q3-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-09,Q3-2025,2025,CYBER_TECH,Claims,4656000,4702560 +2025-09,Q3-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-09,Q3-2025,2025,CYBER_TECH,ExternalCost,1000000,1010000 +2025-09,Q3-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-09,Q3-2025,2025,CYBER_TECH,Premium,10000000,10100000 +2025-09,Q3-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-09,Q3-2025,2025,ENERGY_MINING,Claims,23031067,23261378 +2025-09,Q3-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-09,Q3-2025,2025,ENERGY_MINING,ExternalCost,3300000,3333000 +2025-09,Q3-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-09,Q3-2025,2025,ENERGY_MINING,Premium,33000000,33330000 +2025-09,Q3-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-09,Q3-2025,2025,HOMEOWNERS,Claims,51605987,52122047 +2025-09,Q3-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-09,Q3-2025,2025,HOMEOWNERS,ExternalCost,6200000,6262000 +2025-09,Q3-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-09,Q3-2025,2025,HOMEOWNERS,Premium,65720000,66377200 +2025-09,Q3-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-09,Q3-2025,2025,LIFE_ANN,Claims,20900000,21109000 +2025-09,Q3-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-09,Q3-2025,2025,LIFE_ANN,ExternalCost,3800000,3838000 +2025-09,Q3-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-09,Q3-2025,2025,LIFE_ANN,Premium,38000000,38380000 +2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11453400 +2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1818000 +2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-09,Q3-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18180000 +2025-09,Q3-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-09,Q3-2025,2025,WORKERS_COMP,Claims,26493600,26758536 +2025-09,Q3-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-09,Q3-2025,2025,WORKERS_COMP,ExternalCost,4200000,4242000 +2025-09,Q3-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-09,Q3-2025,2025,WORKERS_COMP,Premium,42000000,42420000 +2025-10,Q4-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-10,Q4-2025,2025,AGRICULTURE,Claims,9902200,9605134 +2025-10,Q4-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-10,Q4-2025,2025,AGRICULTURE,ExternalCost,1400000,1358000 +2025-10,Q4-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-10,Q4-2025,2025,AGRICULTURE,Premium,14000000,13580000 +2025-10,Q4-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-10,Q4-2025,2025,COMMERCIAL,Claims,31113813,30180399 +2025-10,Q4-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-10,Q4-2025,2025,COMMERCIAL,ExternalCost,4800000,4656000 +2025-10,Q4-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-10,Q4-2025,2025,COMMERCIAL,Premium,48000000,46560000 +2025-10,Q4-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-10,Q4-2025,2025,CYBER_TECH,Claims,5136000,4981920 +2025-10,Q4-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-10,Q4-2025,2025,CYBER_TECH,ExternalCost,1000000,970000 +2025-10,Q4-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-10,Q4-2025,2025,CYBER_TECH,Premium,10000000,9700000 +2025-10,Q4-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-10,Q4-2025,2025,ENERGY_MINING,Claims,21183067,20547575 +2025-10,Q4-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-10,Q4-2025,2025,ENERGY_MINING,ExternalCost,3300000,3201000 +2025-10,Q4-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-10,Q4-2025,2025,ENERGY_MINING,Premium,33000000,32010000 +2025-10,Q4-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-10,Q4-2025,2025,HOMEOWNERS,Claims,48360101,46909298 +2025-10,Q4-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-10,Q4-2025,2025,HOMEOWNERS,ExternalCost,6200000,6014000 +2025-10,Q4-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-10,Q4-2025,2025,HOMEOWNERS,Premium,63240000,61342800 +2025-10,Q4-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-10,Q4-2025,2025,LIFE_ANN,Claims,20900000,20273000 +2025-10,Q4-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-10,Q4-2025,2025,LIFE_ANN,ExternalCost,3800000,3686000 +2025-10,Q4-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-10,Q4-2025,2025,LIFE_ANN,Premium,38000000,36860000 +2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,10999800 +2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1746000 +2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-10,Q4-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,17460000 +2025-10,Q4-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-10,Q4-2025,2025,WORKERS_COMP,Claims,25384800,24623256 +2025-10,Q4-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-10,Q4-2025,2025,WORKERS_COMP,ExternalCost,4200000,4074000 +2025-10,Q4-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-10,Q4-2025,2025,WORKERS_COMP,Premium,42000000,40740000 +2025-11,Q4-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-11,Q4-2025,2025,AGRICULTURE,Claims,8919400,9186982 +2025-11,Q4-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-11,Q4-2025,2025,AGRICULTURE,ExternalCost,1400000,1442000 +2025-11,Q4-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-11,Q4-2025,2025,AGRICULTURE,Premium,14000000,14420000 +2025-11,Q4-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-11,Q4-2025,2025,COMMERCIAL,Claims,29885013,30781563 +2025-11,Q4-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-11,Q4-2025,2025,COMMERCIAL,ExternalCost,4800000,4944000 +2025-11,Q4-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-11,Q4-2025,2025,COMMERCIAL,Premium,48000000,49440000 +2025-11,Q4-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-11,Q4-2025,2025,CYBER_TECH,Claims,5424000,5586720 +2025-11,Q4-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-11,Q4-2025,2025,CYBER_TECH,ExternalCost,1000000,1030000 +2025-11,Q4-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-11,Q4-2025,2025,CYBER_TECH,Premium,10000000,10300000 +2025-11,Q4-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-11,Q4-2025,2025,ENERGY_MINING,Claims,20443867,21057183 +2025-11,Q4-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-11,Q4-2025,2025,ENERGY_MINING,ExternalCost,3300000,3399000 +2025-11,Q4-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-11,Q4-2025,2025,ENERGY_MINING,Premium,33000000,33990000 +2025-11,Q4-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-11,Q4-2025,2025,HOMEOWNERS,Claims,41991600,43251348 +2025-11,Q4-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-11,Q4-2025,2025,HOMEOWNERS,ExternalCost,6200000,6386000 +2025-11,Q4-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-11,Q4-2025,2025,HOMEOWNERS,Premium,58900000,60667000 +2025-11,Q4-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-11,Q4-2025,2025,LIFE_ANN,Claims,20900000,21527000 +2025-11,Q4-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-11,Q4-2025,2025,LIFE_ANN,ExternalCost,3800000,3914000 +2025-11,Q4-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-11,Q4-2025,2025,LIFE_ANN,Premium,38000000,39140000 +2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11680200 +2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1854000 +2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-11,Q4-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18540000 +2025-11,Q4-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-11,Q4-2025,2025,WORKERS_COMP,Claims,23610720,24319042 +2025-11,Q4-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-11,Q4-2025,2025,WORKERS_COMP,ExternalCost,4200000,4326000 +2025-11,Q4-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-11,Q4-2025,2025,WORKERS_COMP,Premium,42000000,43260000 +2025-12,Q4-2025,2025,AGRICULTURE,CapitalCost,770000, +2025-12,Q4-2025,2025,AGRICULTURE,Claims,7936600,7936600 +2025-12,Q4-2025,2025,AGRICULTURE,ExpectedProfit,700000, +2025-12,Q4-2025,2025,AGRICULTURE,ExternalCost,1400000,1400000 +2025-12,Q4-2025,2025,AGRICULTURE,InternalCost,1680000, +2025-12,Q4-2025,2025,AGRICULTURE,Premium,14000000,14000000 +2025-12,Q4-2025,2025,COMMERCIAL,CapitalCost,2640000, +2025-12,Q4-2025,2025,COMMERCIAL,Claims,29393493,29393493 +2025-12,Q4-2025,2025,COMMERCIAL,ExpectedProfit,2400000, +2025-12,Q4-2025,2025,COMMERCIAL,ExternalCost,4800000,4800000 +2025-12,Q4-2025,2025,COMMERCIAL,InternalCost,5760000, +2025-12,Q4-2025,2025,COMMERCIAL,Premium,48000000,48000000 +2025-12,Q4-2025,2025,CYBER_TECH,CapitalCost,550000, +2025-12,Q4-2025,2025,CYBER_TECH,Claims,5904000,5904000 +2025-12,Q4-2025,2025,CYBER_TECH,ExpectedProfit,500000, +2025-12,Q4-2025,2025,CYBER_TECH,ExternalCost,1000000,1000000 +2025-12,Q4-2025,2025,CYBER_TECH,InternalCost,1200000, +2025-12,Q4-2025,2025,CYBER_TECH,Premium,10000000,10000000 +2025-12,Q4-2025,2025,ENERGY_MINING,CapitalCost,1815000, +2025-12,Q4-2025,2025,ENERGY_MINING,Claims,21737467,21737467 +2025-12,Q4-2025,2025,ENERGY_MINING,ExpectedProfit,1650000, +2025-12,Q4-2025,2025,ENERGY_MINING,ExternalCost,3300000,3300000 +2025-12,Q4-2025,2025,ENERGY_MINING,InternalCost,3960000, +2025-12,Q4-2025,2025,ENERGY_MINING,Premium,33000000,33000000 +2025-12,Q4-2025,2025,HOMEOWNERS,CapitalCost,3410000, +2025-12,Q4-2025,2025,HOMEOWNERS,Claims,40578139,40578139 +2025-12,Q4-2025,2025,HOMEOWNERS,ExpectedProfit,3100000, +2025-12,Q4-2025,2025,HOMEOWNERS,ExternalCost,6200000,6200000 +2025-12,Q4-2025,2025,HOMEOWNERS,InternalCost,7440000, +2025-12,Q4-2025,2025,HOMEOWNERS,Premium,54560000,54560000 +2025-12,Q4-2025,2025,LIFE_ANN,CapitalCost,2090000, +2025-12,Q4-2025,2025,LIFE_ANN,Claims,20900000,20900000 +2025-12,Q4-2025,2025,LIFE_ANN,ExpectedProfit,1900000, +2025-12,Q4-2025,2025,LIFE_ANN,ExternalCost,3800000,3800000 +2025-12,Q4-2025,2025,LIFE_ANN,InternalCost,4560000, +2025-12,Q4-2025,2025,LIFE_ANN,Premium,38000000,38000000 +2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,CapitalCost,990000, +2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,Claims,11340000,11340000 +2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,ExternalCost,1800000,1800000 +2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,InternalCost,2160000, +2025-12,Q4-2025,2025,SPECIALTY_AVTN_US,Premium,18000000,18000000 +2025-12,Q4-2025,2025,WORKERS_COMP,CapitalCost,2310000, +2025-12,Q4-2025,2025,WORKERS_COMP,Claims,22723680,22723680 +2025-12,Q4-2025,2025,WORKERS_COMP,ExpectedProfit,2100000, +2025-12,Q4-2025,2025,WORKERS_COMP,ExternalCost,4200000,4200000 +2025-12,Q4-2025,2025,WORKERS_COMP,InternalCost,5040000, +2025-12,Q4-2025,2025,WORKERS_COMP,Premium,42000000,42000000 +2026-01,Q1-2026,2026,AGRICULTURE,CapitalCost,770000, +2026-01,Q1-2026,2026,AGRICULTURE,Claims,7936600,7619136 +2026-01,Q1-2026,2026,AGRICULTURE,ExpectedProfit,700000, +2026-01,Q1-2026,2026,AGRICULTURE,ExternalCost,1400000,1344000 +2026-01,Q1-2026,2026,AGRICULTURE,InternalCost,1680000, +2026-01,Q1-2026,2026,AGRICULTURE,Premium,14000000,13440000 +2026-01,Q1-2026,2026,COMMERCIAL,CapitalCost,2640000, +2026-01,Q1-2026,2026,COMMERCIAL,Claims,31113813,29869260 +2026-01,Q1-2026,2026,COMMERCIAL,ExpectedProfit,2400000, +2026-01,Q1-2026,2026,COMMERCIAL,ExternalCost,4800000,4608000 +2026-01,Q1-2026,2026,COMMERCIAL,InternalCost,5760000, +2026-01,Q1-2026,2026,COMMERCIAL,Premium,48000000,46080000 +2026-01,Q1-2026,2026,CYBER_TECH,CapitalCost,550000, +2026-01,Q1-2026,2026,CYBER_TECH,Claims,5424000,5207040 +2026-01,Q1-2026,2026,CYBER_TECH,ExpectedProfit,500000, +2026-01,Q1-2026,2026,CYBER_TECH,ExternalCost,1000000,960000 +2026-01,Q1-2026,2026,CYBER_TECH,InternalCost,1200000, +2026-01,Q1-2026,2026,CYBER_TECH,Premium,10000000,9600000 +2026-01,Q1-2026,2026,ENERGY_MINING,CapitalCost,1815000, +2026-01,Q1-2026,2026,ENERGY_MINING,Claims,22291867,21400192 +2026-01,Q1-2026,2026,ENERGY_MINING,ExpectedProfit,1650000, +2026-01,Q1-2026,2026,ENERGY_MINING,ExternalCost,3300000,3168000 +2026-01,Q1-2026,2026,ENERGY_MINING,InternalCost,3960000, +2026-01,Q1-2026,2026,ENERGY_MINING,Premium,33000000,31680000 +2026-01,Q1-2026,2026,HOMEOWNERS,CapitalCost,3410000, +2026-01,Q1-2026,2026,HOMEOWNERS,Claims,41745056,40075254 +2026-01,Q1-2026,2026,HOMEOWNERS,ExpectedProfit,3100000, +2026-01,Q1-2026,2026,HOMEOWNERS,ExternalCost,6200000,5952000 +2026-01,Q1-2026,2026,HOMEOWNERS,InternalCost,7440000, +2026-01,Q1-2026,2026,HOMEOWNERS,Premium,57660000,55353600 +2026-01,Q1-2026,2026,LIFE_ANN,CapitalCost,2090000, +2026-01,Q1-2026,2026,LIFE_ANN,Claims,20900000,20064000 +2026-01,Q1-2026,2026,LIFE_ANN,ExpectedProfit,1900000, +2026-01,Q1-2026,2026,LIFE_ANN,ExternalCost,3800000,3648000 +2026-01,Q1-2026,2026,LIFE_ANN,InternalCost,4560000, +2026-01,Q1-2026,2026,LIFE_ANN,Premium,38000000,36480000 +2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,CapitalCost,990000, +2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,Claims,11340000,10886400 +2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,ExternalCost,1800000,1728000 +2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,InternalCost,2160000, +2026-01,Q1-2026,2026,SPECIALTY_AVTN_US,Premium,18000000,17280000 +2026-01,Q1-2026,2026,WORKERS_COMP,CapitalCost,2310000, +2026-01,Q1-2026,2026,WORKERS_COMP,Claims,24276000,23304960 +2026-01,Q1-2026,2026,WORKERS_COMP,ExpectedProfit,2100000, +2026-01,Q1-2026,2026,WORKERS_COMP,ExternalCost,4200000,4032000 +2026-01,Q1-2026,2026,WORKERS_COMP,InternalCost,5040000, +2026-01,Q1-2026,2026,WORKERS_COMP,Premium,42000000,40320000 +2026-02,Q1-2026,2026,AGRICULTURE,CapitalCost,770000, +2026-02,Q1-2026,2026,AGRICULTURE,Claims,8264200,8429484 +2026-02,Q1-2026,2026,AGRICULTURE,ExpectedProfit,700000, +2026-02,Q1-2026,2026,AGRICULTURE,ExternalCost,1400000,1428000 +2026-02,Q1-2026,2026,AGRICULTURE,InternalCost,1680000, +2026-02,Q1-2026,2026,AGRICULTURE,Premium,14000000,14280000 +2026-02,Q1-2026,2026,COMMERCIAL,CapitalCost,2640000, +2026-02,Q1-2026,2026,COMMERCIAL,Claims,29885013,30482713 +2026-02,Q1-2026,2026,COMMERCIAL,ExpectedProfit,2400000, +2026-02,Q1-2026,2026,COMMERCIAL,ExternalCost,4800000,4896000 +2026-02,Q1-2026,2026,COMMERCIAL,InternalCost,5760000, +2026-02,Q1-2026,2026,COMMERCIAL,Premium,48000000,48960000 +2026-02,Q1-2026,2026,CYBER_TECH,CapitalCost,550000, +2026-02,Q1-2026,2026,CYBER_TECH,Claims,4944000,5042880 +2026-02,Q1-2026,2026,CYBER_TECH,ExpectedProfit,500000, +2026-02,Q1-2026,2026,CYBER_TECH,ExternalCost,1000000,1020000 +2026-02,Q1-2026,2026,CYBER_TECH,InternalCost,1200000, +2026-02,Q1-2026,2026,CYBER_TECH,Premium,10000000,10200000 +2026-02,Q1-2026,2026,ENERGY_MINING,CapitalCost,1815000, +2026-02,Q1-2026,2026,ENERGY_MINING,Claims,21183067,21606728 +2026-02,Q1-2026,2026,ENERGY_MINING,ExpectedProfit,1650000, +2026-02,Q1-2026,2026,ENERGY_MINING,ExternalCost,3300000,3366000 +2026-02,Q1-2026,2026,ENERGY_MINING,InternalCost,3960000, +2026-02,Q1-2026,2026,ENERGY_MINING,Premium,33000000,33660000 +2026-02,Q1-2026,2026,HOMEOWNERS,CapitalCost,3410000, +2026-02,Q1-2026,2026,HOMEOWNERS,Claims,39998842,40798819 +2026-02,Q1-2026,2026,HOMEOWNERS,ExpectedProfit,3100000, +2026-02,Q1-2026,2026,HOMEOWNERS,ExternalCost,6200000,6324000 +2026-02,Q1-2026,2026,HOMEOWNERS,InternalCost,7440000, +2026-02,Q1-2026,2026,HOMEOWNERS,Premium,55800000,56916000 +2026-02,Q1-2026,2026,LIFE_ANN,CapitalCost,2090000, +2026-02,Q1-2026,2026,LIFE_ANN,Claims,20900000,21318000 +2026-02,Q1-2026,2026,LIFE_ANN,ExpectedProfit,1900000, +2026-02,Q1-2026,2026,LIFE_ANN,ExternalCost,3800000,3876000 +2026-02,Q1-2026,2026,LIFE_ANN,InternalCost,4560000, +2026-02,Q1-2026,2026,LIFE_ANN,Premium,38000000,38760000 +2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,CapitalCost,990000, +2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,Claims,11340000,11566800 +2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,ExpectedProfit,900000, +2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,ExternalCost,1800000,1836000 +2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,InternalCost,2160000, +2026-02,Q1-2026,2026,SPECIALTY_AVTN_US,Premium,18000000,18360000 +2026-02,Q1-2026,2026,WORKERS_COMP,CapitalCost,2310000, +2026-02,Q1-2026,2026,WORKERS_COMP,Claims,23167200,23630544 +2026-02,Q1-2026,2026,WORKERS_COMP,ExpectedProfit,2100000, +2026-02,Q1-2026,2026,WORKERS_COMP,ExternalCost,4200000,4284000 +2026-02,Q1-2026,2026,WORKERS_COMP,InternalCost,5040000, +2026-02,Q1-2026,2026,WORKERS_COMP,Premium,42000000,42840000 diff --git a/samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv b/samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv new file mode 100644 index 000000000..8ad3259b3 --- /dev/null +++ b/samples/Graph/attachments/FutuRe/AsiaRe/Analysis/datacube.csv @@ -0,0 +1,865 @@ +Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual +2024-09,Q3-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, +2024-09,Q3-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2449442168 +2024-09,Q3-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2024-09,Q3-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,414330739 +2024-09,Q3-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, +2024-09,Q3-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4223423702 +2024-09,Q3-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, +2024-09,Q3-2024,2024,CYBER_DIGITAL,Claims,720000000,740820742 +2024-09,Q3-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, +2024-09,Q3-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,151590295 +2024-09,Q3-2024,2024,CYBER_DIGITAL,InternalCost,180000000, +2024-09,Q3-2024,2024,CYBER_DIGITAL,Premium,1500000000,1483392644 +2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5486579879 +2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,776345941 +2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2024-09,Q3-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7922360025 +2024-09,Q3-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, +2024-09,Q3-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1244238708 +2024-09,Q3-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2024-09,Q3-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,180057837 +2024-09,Q3-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, +2024-09,Q3-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1766145400 +2024-09,Q3-2024,2024,MOTOR_TPL,CapitalCost,247500000, +2024-09,Q3-2024,2024,MOTOR_TPL,Claims,3330000000,3283070350 +2024-09,Q3-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, +2024-09,Q3-2024,2024,MOTOR_TPL,ExternalCost,450000000,454046880 +2024-09,Q3-2024,2024,MOTOR_TPL,InternalCost,540000000, +2024-09,Q3-2024,2024,MOTOR_TPL,Premium,4500000000,4414776475 +2024-09,Q3-2024,2024,PADDY_CROP,CapitalCost,132000000, +2024-09,Q3-2024,2024,PADDY_CROP,Claims,1872000000,1925888737 +2024-09,Q3-2024,2024,PADDY_CROP,ExpectedProfit,120000000, +2024-09,Q3-2024,2024,PADDY_CROP,ExternalCost,240000000,241285426 +2024-09,Q3-2024,2024,PADDY_CROP,InternalCost,288000000, +2024-09,Q3-2024,2024,PADDY_CROP,Premium,2400000000,2404314382 +2024-09,Q3-2024,2024,TRADE_CREDIT,CapitalCost,115500000, +2024-09,Q3-2024,2024,TRADE_CREDIT,Claims,1155000000,1120950485 +2024-09,Q3-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, +2024-09,Q3-2024,2024,TRADE_CREDIT,ExternalCost,210000000,213853323 +2024-09,Q3-2024,2024,TRADE_CREDIT,InternalCost,252000000, +2024-09,Q3-2024,2024,TRADE_CREDIT,Premium,2100000000,2125992158 +2024-09,Q3-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, +2024-09,Q3-2024,2024,TYPHOON_FLOOD,Claims,5814000000,6377621052 +2024-09,Q3-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, +2024-09,Q3-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,558217399 +2024-09,Q3-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, +2024-09,Q3-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5745175782 +2024-10,Q4-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, +2024-10,Q4-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2512257460 +2024-10,Q4-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2024-10,Q4-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,409737195 +2024-10,Q4-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, +2024-10,Q4-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4276811796 +2024-10,Q4-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, +2024-10,Q4-2024,2024,CYBER_DIGITAL,Claims,720000000,747215676 +2024-10,Q4-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, +2024-10,Q4-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,150933534 +2024-10,Q4-2024,2024,CYBER_DIGITAL,InternalCost,180000000, +2024-10,Q4-2024,2024,CYBER_DIGITAL,Premium,1500000000,1475802983 +2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5775373897 +2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,781695475 +2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2024-10,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7895824021 +2024-10,Q4-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, +2024-10,Q4-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1260356265 +2024-10,Q4-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2024-10,Q4-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,180562039 +2024-10,Q4-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, +2024-10,Q4-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1834064335 +2024-10,Q4-2024,2024,MOTOR_TPL,CapitalCost,247500000, +2024-10,Q4-2024,2024,MOTOR_TPL,Claims,3330000000,3394873662 +2024-10,Q4-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, +2024-10,Q4-2024,2024,MOTOR_TPL,ExternalCost,450000000,459766086 +2024-10,Q4-2024,2024,MOTOR_TPL,InternalCost,540000000, +2024-10,Q4-2024,2024,MOTOR_TPL,Premium,4500000000,4559292840 +2024-10,Q4-2024,2024,PADDY_CROP,CapitalCost,132000000, +2024-10,Q4-2024,2024,PADDY_CROP,Claims,1560000000,1601130565 +2024-10,Q4-2024,2024,PADDY_CROP,ExpectedProfit,120000000, +2024-10,Q4-2024,2024,PADDY_CROP,ExternalCost,240000000,233459871 +2024-10,Q4-2024,2024,PADDY_CROP,InternalCost,288000000, +2024-10,Q4-2024,2024,PADDY_CROP,Premium,2400000000,2407425806 +2024-10,Q4-2024,2024,TRADE_CREDIT,CapitalCost,115500000, +2024-10,Q4-2024,2024,TRADE_CREDIT,Claims,1155000000,1147089448 +2024-10,Q4-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, +2024-10,Q4-2024,2024,TRADE_CREDIT,ExternalCost,210000000,204705379 +2024-10,Q4-2024,2024,TRADE_CREDIT,InternalCost,252000000, +2024-10,Q4-2024,2024,TRADE_CREDIT,Premium,2100000000,2077143455 +2024-10,Q4-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, +2024-10,Q4-2024,2024,TYPHOON_FLOOD,Claims,3876000000,3791038523 +2024-10,Q4-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, +2024-10,Q4-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,562406697 +2024-10,Q4-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, +2024-10,Q4-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5639076322 +2024-11,Q4-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, +2024-11,Q4-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2517950167 +2024-11,Q4-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2024-11,Q4-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,416728560 +2024-11,Q4-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, +2024-11,Q4-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4222794987 +2024-11,Q4-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, +2024-11,Q4-2024,2024,CYBER_DIGITAL,Claims,720000000,713777923 +2024-11,Q4-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, +2024-11,Q4-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,153929891 +2024-11,Q4-2024,2024,CYBER_DIGITAL,InternalCost,180000000, +2024-11,Q4-2024,2024,CYBER_DIGITAL,Premium,1500000000,1482570422 +2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5721190378 +2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,764609289 +2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2024-11,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7846187040 +2024-11,Q4-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, +2024-11,Q4-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1238670971 +2024-11,Q4-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2024-11,Q4-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,178698119 +2024-11,Q4-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, +2024-11,Q4-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1816497129 +2024-11,Q4-2024,2024,MOTOR_TPL,CapitalCost,247500000, +2024-11,Q4-2024,2024,MOTOR_TPL,Claims,3330000000,3400595936 +2024-11,Q4-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, +2024-11,Q4-2024,2024,MOTOR_TPL,ExternalCost,450000000,451537643 +2024-11,Q4-2024,2024,MOTOR_TPL,InternalCost,540000000, +2024-11,Q4-2024,2024,MOTOR_TPL,Premium,4500000000,4588114203 +2024-11,Q4-2024,2024,PADDY_CROP,CapitalCost,132000000, +2024-11,Q4-2024,2024,PADDY_CROP,Claims,1560000000,1618387920 +2024-11,Q4-2024,2024,PADDY_CROP,ExpectedProfit,120000000, +2024-11,Q4-2024,2024,PADDY_CROP,ExternalCost,240000000,243974399 +2024-11,Q4-2024,2024,PADDY_CROP,InternalCost,288000000, +2024-11,Q4-2024,2024,PADDY_CROP,Premium,2400000000,2417722968 +2024-11,Q4-2024,2024,TRADE_CREDIT,CapitalCost,115500000, +2024-11,Q4-2024,2024,TRADE_CREDIT,Claims,1155000000,1123316063 +2024-11,Q4-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, +2024-11,Q4-2024,2024,TRADE_CREDIT,ExternalCost,210000000,207674708 +2024-11,Q4-2024,2024,TRADE_CREDIT,InternalCost,252000000, +2024-11,Q4-2024,2024,TRADE_CREDIT,Premium,2100000000,2077240038 +2024-11,Q4-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, +2024-11,Q4-2024,2024,TYPHOON_FLOOD,Claims,3876000000,3825141560 +2024-11,Q4-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, +2024-11,Q4-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,585147512 +2024-11,Q4-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, +2024-11,Q4-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5647044920 +2024-12,Q4-2024,2024,CONSTRUCTION_ENG,CapitalCost,231000000, +2024-12,Q4-2024,2024,CONSTRUCTION_ENG,Claims,2520000000,2507839061 +2024-12,Q4-2024,2024,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2024-12,Q4-2024,2024,CONSTRUCTION_ENG,ExternalCost,420000000,423917054 +2024-12,Q4-2024,2024,CONSTRUCTION_ENG,InternalCost,504000000, +2024-12,Q4-2024,2024,CONSTRUCTION_ENG,Premium,4200000000,4263229761 +2024-12,Q4-2024,2024,CYBER_DIGITAL,CapitalCost,82500000, +2024-12,Q4-2024,2024,CYBER_DIGITAL,Claims,720000000,751077941 +2024-12,Q4-2024,2024,CYBER_DIGITAL,ExpectedProfit,75000000, +2024-12,Q4-2024,2024,CYBER_DIGITAL,ExternalCost,150000000,149629667 +2024-12,Q4-2024,2024,CYBER_DIGITAL,InternalCost,180000000, +2024-12,Q4-2024,2024,CYBER_DIGITAL,Premium,1500000000,1493737914 +2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Claims,5616000000,5558324807 +2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,782872029 +2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2024-12,Q4-2024,2024,EARTHQUAKE_VOLCANIC,Premium,7800000000,7726642612 +2024-12,Q4-2024,2024,MICRO_HEALTH_PA,CapitalCost,99000000, +2024-12,Q4-2024,2024,MICRO_HEALTH_PA,Claims,1260000000,1281126268 +2024-12,Q4-2024,2024,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2024-12,Q4-2024,2024,MICRO_HEALTH_PA,ExternalCost,180000000,184296487 +2024-12,Q4-2024,2024,MICRO_HEALTH_PA,InternalCost,216000000, +2024-12,Q4-2024,2024,MICRO_HEALTH_PA,Premium,1800000000,1782917396 +2024-12,Q4-2024,2024,MOTOR_TPL,CapitalCost,247500000, +2024-12,Q4-2024,2024,MOTOR_TPL,Claims,3330000000,3288527050 +2024-12,Q4-2024,2024,MOTOR_TPL,ExpectedProfit,225000000, +2024-12,Q4-2024,2024,MOTOR_TPL,ExternalCost,450000000,463433515 +2024-12,Q4-2024,2024,MOTOR_TPL,InternalCost,540000000, +2024-12,Q4-2024,2024,MOTOR_TPL,Premium,4500000000,4481892091 +2024-12,Q4-2024,2024,PADDY_CROP,CapitalCost,132000000, +2024-12,Q4-2024,2024,PADDY_CROP,Claims,1560000000,1524545495 +2024-12,Q4-2024,2024,PADDY_CROP,ExpectedProfit,120000000, +2024-12,Q4-2024,2024,PADDY_CROP,ExternalCost,240000000,233478476 +2024-12,Q4-2024,2024,PADDY_CROP,InternalCost,288000000, +2024-12,Q4-2024,2024,PADDY_CROP,Premium,2400000000,2400914524 +2024-12,Q4-2024,2024,TRADE_CREDIT,CapitalCost,115500000, +2024-12,Q4-2024,2024,TRADE_CREDIT,Claims,1155000000,1178326014 +2024-12,Q4-2024,2024,TRADE_CREDIT,ExpectedProfit,105000000, +2024-12,Q4-2024,2024,TRADE_CREDIT,ExternalCost,210000000,213680200 +2024-12,Q4-2024,2024,TRADE_CREDIT,InternalCost,252000000, +2024-12,Q4-2024,2024,TRADE_CREDIT,Premium,2100000000,2067210527 +2024-12,Q4-2024,2024,TYPHOON_FLOOD,CapitalCost,313500000, +2024-12,Q4-2024,2024,TYPHOON_FLOOD,Claims,3876000000,3779418671 +2024-12,Q4-2024,2024,TYPHOON_FLOOD,ExpectedProfit,285000000, +2024-12,Q4-2024,2024,TYPHOON_FLOOD,ExternalCost,570000000,565951380 +2024-12,Q4-2024,2024,TYPHOON_FLOOD,InternalCost,684000000, +2024-12,Q4-2024,2024,TYPHOON_FLOOD,Premium,5700000000,5682252472 +2025-01,Q1-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-01,Q1-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2551069452 +2025-01,Q1-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-01,Q1-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,431871175 +2025-01,Q1-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-01,Q1-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4283348392 +2025-01,Q1-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-01,Q1-2025,2025,CYBER_DIGITAL,Claims,720000000,699061307 +2025-01,Q1-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-01,Q1-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,151986496 +2025-01,Q1-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-01,Q1-2025,2025,CYBER_DIGITAL,Premium,1500000000,1521646782 +2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Claims,14040000000,15928556084 +2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,769087419 +2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-01,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7856693635 +2025-01,Q1-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-01,Q1-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1233444459 +2025-01,Q1-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-01,Q1-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,179295465 +2025-01,Q1-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-01,Q1-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1810149249 +2025-01,Q1-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-01,Q1-2025,2025,MOTOR_TPL,Claims,3330000000,3484196563 +2025-01,Q1-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-01,Q1-2025,2025,MOTOR_TPL,ExternalCost,450000000,460148029 +2025-01,Q1-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-01,Q1-2025,2025,MOTOR_TPL,Premium,4500000000,4491670267 +2025-01,Q1-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-01,Q1-2025,2025,PADDY_CROP,Claims,1560000000,1575673147 +2025-01,Q1-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-01,Q1-2025,2025,PADDY_CROP,ExternalCost,240000000,235372587 +2025-01,Q1-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-01,Q1-2025,2025,PADDY_CROP,Premium,2400000000,2377285349 +2025-01,Q1-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-01,Q1-2025,2025,TRADE_CREDIT,Claims,1155000000,1200785916 +2025-01,Q1-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-01,Q1-2025,2025,TRADE_CREDIT,ExternalCost,210000000,207460404 +2025-01,Q1-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-01,Q1-2025,2025,TRADE_CREDIT,Premium,2100000000,2134660739 +2025-01,Q1-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-01,Q1-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3948549483 +2025-01,Q1-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-01,Q1-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,558127103 +2025-01,Q1-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-01,Q1-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5731680485 +2025-02,Q1-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-02,Q1-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2553138812 +2025-02,Q1-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-02,Q1-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,427021387 +2025-02,Q1-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-02,Q1-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4244101814 +2025-02,Q1-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-02,Q1-2025,2025,CYBER_DIGITAL,Claims,720000000,698432941 +2025-02,Q1-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-02,Q1-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,148417405 +2025-02,Q1-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-02,Q1-2025,2025,CYBER_DIGITAL,Premium,1500000000,1501821220 +2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5864945426 +2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,797724184 +2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-02,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7650076744 +2025-02,Q1-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-02,Q1-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1253197424 +2025-02,Q1-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-02,Q1-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,175225592 +2025-02,Q1-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-02,Q1-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1823879918 +2025-02,Q1-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-02,Q1-2025,2025,MOTOR_TPL,Claims,3330000000,3482367332 +2025-02,Q1-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-02,Q1-2025,2025,MOTOR_TPL,ExternalCost,450000000,438812643 +2025-02,Q1-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-02,Q1-2025,2025,MOTOR_TPL,Premium,4500000000,4568041728 +2025-02,Q1-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-02,Q1-2025,2025,PADDY_CROP,Claims,1560000000,1521837722 +2025-02,Q1-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-02,Q1-2025,2025,PADDY_CROP,ExternalCost,240000000,243752671 +2025-02,Q1-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-02,Q1-2025,2025,PADDY_CROP,Premium,2400000000,2398655084 +2025-02,Q1-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-02,Q1-2025,2025,TRADE_CREDIT,Claims,1155000000,1132213371 +2025-02,Q1-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-02,Q1-2025,2025,TRADE_CREDIT,ExternalCost,210000000,209688558 +2025-02,Q1-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-02,Q1-2025,2025,TRADE_CREDIT,Premium,2100000000,2122330092 +2025-02,Q1-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-02,Q1-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3841908760 +2025-02,Q1-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-02,Q1-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,582737210 +2025-02,Q1-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-02,Q1-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5711355219 +2025-03,Q1-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-03,Q1-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2487098518 +2025-03,Q1-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-03,Q1-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,420990261 +2025-03,Q1-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-03,Q1-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4187087174 +2025-03,Q1-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-03,Q1-2025,2025,CYBER_DIGITAL,Claims,720000000,709986301 +2025-03,Q1-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-03,Q1-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,148305447 +2025-03,Q1-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-03,Q1-2025,2025,CYBER_DIGITAL,Premium,1500000000,1513795864 +2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5739497214 +2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,777103084 +2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-03,Q1-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7954486599 +2025-03,Q1-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-03,Q1-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1234397223 +2025-03,Q1-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-03,Q1-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,177026731 +2025-03,Q1-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-03,Q1-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1801265461 +2025-03,Q1-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-03,Q1-2025,2025,MOTOR_TPL,Claims,3330000000,3386825443 +2025-03,Q1-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-03,Q1-2025,2025,MOTOR_TPL,ExternalCost,450000000,442713098 +2025-03,Q1-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-03,Q1-2025,2025,MOTOR_TPL,Premium,4500000000,4470855401 +2025-03,Q1-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-03,Q1-2025,2025,PADDY_CROP,Claims,1560000000,1522059937 +2025-03,Q1-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-03,Q1-2025,2025,PADDY_CROP,ExternalCost,240000000,241887883 +2025-03,Q1-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-03,Q1-2025,2025,PADDY_CROP,Premium,2400000000,2373140869 +2025-03,Q1-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-03,Q1-2025,2025,TRADE_CREDIT,Claims,1155000000,1204010809 +2025-03,Q1-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-03,Q1-2025,2025,TRADE_CREDIT,ExternalCost,210000000,214531406 +2025-03,Q1-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-03,Q1-2025,2025,TRADE_CREDIT,Premium,2100000000,2077231110 +2025-03,Q1-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-03,Q1-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3833520477 +2025-03,Q1-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-03,Q1-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,575779040 +2025-03,Q1-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-03,Q1-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5602155476 +2025-04,Q2-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-04,Q2-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2471074069 +2025-04,Q2-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-04,Q2-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,430974959 +2025-04,Q2-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-04,Q2-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4151991784 +2025-04,Q2-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-04,Q2-2025,2025,CYBER_DIGITAL,Claims,720000000,725625851 +2025-04,Q2-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-04,Q2-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,152561575 +2025-04,Q2-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-04,Q2-2025,2025,CYBER_DIGITAL,Premium,1500000000,1504262586 +2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5533067366 +2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,761136362 +2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-04,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7895939063 +2025-04,Q2-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-04,Q2-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1264896725 +2025-04,Q2-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-04,Q2-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,179643866 +2025-04,Q2-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-04,Q2-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1795035685 +2025-04,Q2-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-04,Q2-2025,2025,MOTOR_TPL,Claims,3330000000,3409484315 +2025-04,Q2-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-04,Q2-2025,2025,MOTOR_TPL,ExternalCost,450000000,463072461 +2025-04,Q2-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-04,Q2-2025,2025,MOTOR_TPL,Premium,4500000000,4541233653 +2025-04,Q2-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-04,Q2-2025,2025,PADDY_CROP,Claims,1560000000,1563447136 +2025-04,Q2-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-04,Q2-2025,2025,PADDY_CROP,ExternalCost,240000000,237685958 +2025-04,Q2-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-04,Q2-2025,2025,PADDY_CROP,Premium,2400000000,2361448116 +2025-04,Q2-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-04,Q2-2025,2025,TRADE_CREDIT,Claims,1155000000,1143325845 +2025-04,Q2-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-04,Q2-2025,2025,TRADE_CREDIT,ExternalCost,210000000,206096632 +2025-04,Q2-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-04,Q2-2025,2025,TRADE_CREDIT,Premium,2100000000,2130380493 +2025-04,Q2-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-04,Q2-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3890537059 +2025-04,Q2-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-04,Q2-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,562426244 +2025-04,Q2-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-04,Q2-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5688283889 +2025-05,Q2-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-05,Q2-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2630530345 +2025-05,Q2-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-05,Q2-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,418566895 +2025-05,Q2-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-05,Q2-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4157967483 +2025-05,Q2-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-05,Q2-2025,2025,CYBER_DIGITAL,Claims,720000000,730098738 +2025-05,Q2-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-05,Q2-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,145955295 +2025-05,Q2-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-05,Q2-2025,2025,CYBER_DIGITAL,Premium,1500000000,1521680946 +2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5823130473 +2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,801949025 +2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-05,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7955776130 +2025-05,Q2-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-05,Q2-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1307748530 +2025-05,Q2-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-05,Q2-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,176396160 +2025-05,Q2-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-05,Q2-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1830698423 +2025-05,Q2-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-05,Q2-2025,2025,MOTOR_TPL,Claims,3330000000,3287042281 +2025-05,Q2-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-05,Q2-2025,2025,MOTOR_TPL,ExternalCost,450000000,447328088 +2025-05,Q2-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-05,Q2-2025,2025,MOTOR_TPL,Premium,4500000000,4497415403 +2025-05,Q2-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-05,Q2-2025,2025,PADDY_CROP,Claims,1560000000,1560495845 +2025-05,Q2-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-05,Q2-2025,2025,PADDY_CROP,ExternalCost,240000000,246988447 +2025-05,Q2-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-05,Q2-2025,2025,PADDY_CROP,Premium,2400000000,2357628998 +2025-05,Q2-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-05,Q2-2025,2025,TRADE_CREDIT,Claims,1155000000,1192798124 +2025-05,Q2-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-05,Q2-2025,2025,TRADE_CREDIT,ExternalCost,210000000,209433105 +2025-05,Q2-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-05,Q2-2025,2025,TRADE_CREDIT,Premium,2100000000,2080277057 +2025-05,Q2-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-05,Q2-2025,2025,TYPHOON_FLOOD,Claims,3876000000,4056565054 +2025-05,Q2-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-05,Q2-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,586943456 +2025-05,Q2-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-05,Q2-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5682445707 +2025-06,Q2-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-06,Q2-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2589231108 +2025-06,Q2-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-06,Q2-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,411300880 +2025-06,Q2-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-06,Q2-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4209369078 +2025-06,Q2-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-06,Q2-2025,2025,CYBER_DIGITAL,Claims,720000000,754197659 +2025-06,Q2-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-06,Q2-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,150712623 +2025-06,Q2-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-06,Q2-2025,2025,CYBER_DIGITAL,Premium,1500000000,1487802470 +2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5783570460 +2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,759275335 +2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-06,Q2-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7813164903 +2025-06,Q2-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-06,Q2-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1272887319 +2025-06,Q2-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-06,Q2-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,183809375 +2025-06,Q2-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-06,Q2-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1806060787 +2025-06,Q2-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-06,Q2-2025,2025,MOTOR_TPL,Claims,3330000000,3486051500 +2025-06,Q2-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-06,Q2-2025,2025,MOTOR_TPL,ExternalCost,450000000,438663010 +2025-06,Q2-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-06,Q2-2025,2025,MOTOR_TPL,Premium,4500000000,4438337891 +2025-06,Q2-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-06,Q2-2025,2025,PADDY_CROP,Claims,1560000000,1587460381 +2025-06,Q2-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-06,Q2-2025,2025,PADDY_CROP,ExternalCost,240000000,242523061 +2025-06,Q2-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-06,Q2-2025,2025,PADDY_CROP,Premium,2400000000,2369839196 +2025-06,Q2-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-06,Q2-2025,2025,TRADE_CREDIT,Claims,1155000000,1131427523 +2025-06,Q2-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-06,Q2-2025,2025,TRADE_CREDIT,ExternalCost,210000000,214917620 +2025-06,Q2-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-06,Q2-2025,2025,TRADE_CREDIT,Premium,2100000000,2077757127 +2025-06,Q2-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-06,Q2-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3944068499 +2025-06,Q2-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-06,Q2-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,574082848 +2025-06,Q2-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-06,Q2-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5642137099 +2025-07,Q3-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-07,Q3-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2562068334 +2025-07,Q3-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-07,Q3-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,420574124 +2025-07,Q3-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-07,Q3-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4186429786 +2025-07,Q3-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-07,Q3-2025,2025,CYBER_DIGITAL,Claims,720000000,710165330 +2025-07,Q3-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-07,Q3-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,151945726 +2025-07,Q3-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-07,Q3-2025,2025,CYBER_DIGITAL,Premium,1500000000,1526082375 +2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5625338665 +2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,788035102 +2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-07,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7718470017 +2025-07,Q3-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-07,Q3-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1254070661 +2025-07,Q3-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-07,Q3-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,182720137 +2025-07,Q3-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-07,Q3-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1785599790 +2025-07,Q3-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-07,Q3-2025,2025,MOTOR_TPL,Claims,3330000000,3352187263 +2025-07,Q3-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-07,Q3-2025,2025,MOTOR_TPL,ExternalCost,450000000,463458270 +2025-07,Q3-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-07,Q3-2025,2025,MOTOR_TPL,Premium,4500000000,4423057761 +2025-07,Q3-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-07,Q3-2025,2025,PADDY_CROP,Claims,1872000000,1902928672 +2025-07,Q3-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-07,Q3-2025,2025,PADDY_CROP,ExternalCost,240000000,235869422 +2025-07,Q3-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-07,Q3-2025,2025,PADDY_CROP,Premium,2400000000,2447625259 +2025-07,Q3-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-07,Q3-2025,2025,TRADE_CREDIT,Claims,1155000000,1206583167 +2025-07,Q3-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-07,Q3-2025,2025,TRADE_CREDIT,ExternalCost,210000000,214798889 +2025-07,Q3-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-07,Q3-2025,2025,TRADE_CREDIT,Premium,2100000000,2080276835 +2025-07,Q3-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-07,Q3-2025,2025,TYPHOON_FLOOD,Claims,5814000000,6005169587 +2025-07,Q3-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-07,Q3-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,558294942 +2025-07,Q3-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-07,Q3-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5786473615 +2025-08,Q3-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-08,Q3-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2586233649 +2025-08,Q3-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-08,Q3-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,422814280 +2025-08,Q3-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-08,Q3-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4256069152 +2025-08,Q3-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-08,Q3-2025,2025,CYBER_DIGITAL,Claims,720000000,736069036 +2025-08,Q3-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-08,Q3-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,145570408 +2025-08,Q3-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-08,Q3-2025,2025,CYBER_DIGITAL,Premium,1500000000,1529233984 +2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5582024886 +2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,787646592 +2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-08,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7898936490 +2025-08,Q3-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-08,Q3-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1235736544 +2025-08,Q3-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-08,Q3-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,175846630 +2025-08,Q3-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-08,Q3-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1831602960 +2025-08,Q3-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-08,Q3-2025,2025,MOTOR_TPL,Claims,3330000000,3377478778 +2025-08,Q3-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-08,Q3-2025,2025,MOTOR_TPL,ExternalCost,450000000,443853402 +2025-08,Q3-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-08,Q3-2025,2025,MOTOR_TPL,Premium,4500000000,4429266476 +2025-08,Q3-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-08,Q3-2025,2025,PADDY_CROP,Claims,1872000000,2003447501 +2025-08,Q3-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-08,Q3-2025,2025,PADDY_CROP,ExternalCost,240000000,235731801 +2025-08,Q3-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-08,Q3-2025,2025,PADDY_CROP,Premium,2400000000,2410063663 +2025-08,Q3-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-08,Q3-2025,2025,TRADE_CREDIT,Claims,1155000000,1144742113 +2025-08,Q3-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-08,Q3-2025,2025,TRADE_CREDIT,ExternalCost,210000000,209855501 +2025-08,Q3-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-08,Q3-2025,2025,TRADE_CREDIT,Premium,2100000000,2111275989 +2025-08,Q3-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-08,Q3-2025,2025,TYPHOON_FLOOD,Claims,5814000000,6837535727 +2025-08,Q3-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-08,Q3-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,556056608 +2025-08,Q3-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-08,Q3-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5792416720 +2025-09,Q3-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-09,Q3-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2500178733 +2025-09,Q3-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-09,Q3-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,407489351 +2025-09,Q3-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-09,Q3-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4187160730 +2025-09,Q3-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-09,Q3-2025,2025,CYBER_DIGITAL,Claims,720000000,735097731 +2025-09,Q3-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-09,Q3-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,147857597 +2025-09,Q3-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-09,Q3-2025,2025,CYBER_DIGITAL,Premium,1500000000,1516267153 +2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5695378980 +2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,776615748 +2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-09,Q3-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7875264043 +2025-09,Q3-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-09,Q3-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1229784581 +2025-09,Q3-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-09,Q3-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,184137549 +2025-09,Q3-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-09,Q3-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1764696218 +2025-09,Q3-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-09,Q3-2025,2025,MOTOR_TPL,Claims,3330000000,3375445253 +2025-09,Q3-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-09,Q3-2025,2025,MOTOR_TPL,ExternalCost,450000000,459034066 +2025-09,Q3-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-09,Q3-2025,2025,MOTOR_TPL,Premium,4500000000,4572707143 +2025-09,Q3-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-09,Q3-2025,2025,PADDY_CROP,Claims,1872000000,1914602631 +2025-09,Q3-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-09,Q3-2025,2025,PADDY_CROP,ExternalCost,240000000,234635215 +2025-09,Q3-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-09,Q3-2025,2025,PADDY_CROP,Premium,2400000000,2407920918 +2025-09,Q3-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-09,Q3-2025,2025,TRADE_CREDIT,Claims,1155000000,1203415890 +2025-09,Q3-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-09,Q3-2025,2025,TRADE_CREDIT,ExternalCost,210000000,213731141 +2025-09,Q3-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-09,Q3-2025,2025,TRADE_CREDIT,Premium,2100000000,2083893701 +2025-09,Q3-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-09,Q3-2025,2025,TYPHOON_FLOOD,Claims,5814000000,6663456610 +2025-09,Q3-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-09,Q3-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,560084618 +2025-09,Q3-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-09,Q3-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5782240189 +2025-10,Q4-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-10,Q4-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2465123194 +2025-10,Q4-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-10,Q4-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,427058929 +2025-10,Q4-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-10,Q4-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4157920996 +2025-10,Q4-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-10,Q4-2025,2025,CYBER_DIGITAL,Claims,720000000,721807338 +2025-10,Q4-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-10,Q4-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,151085954 +2025-10,Q4-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-10,Q4-2025,2025,CYBER_DIGITAL,Premium,1500000000,1523048082 +2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5865296943 +2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,797063547 +2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-10,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7692220642 +2025-10,Q4-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-10,Q4-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1303925789 +2025-10,Q4-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-10,Q4-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,184119295 +2025-10,Q4-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-10,Q4-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1834286834 +2025-10,Q4-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-10,Q4-2025,2025,MOTOR_TPL,Claims,3330000000,3426320775 +2025-10,Q4-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-10,Q4-2025,2025,MOTOR_TPL,ExternalCost,450000000,445469008 +2025-10,Q4-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-10,Q4-2025,2025,MOTOR_TPL,Premium,4500000000,4414461545 +2025-10,Q4-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-10,Q4-2025,2025,PADDY_CROP,Claims,1560000000,1613318945 +2025-10,Q4-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-10,Q4-2025,2025,PADDY_CROP,ExternalCost,240000000,245242522 +2025-10,Q4-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-10,Q4-2025,2025,PADDY_CROP,Premium,2400000000,2441358325 +2025-10,Q4-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-10,Q4-2025,2025,TRADE_CREDIT,Claims,1155000000,1145002848 +2025-10,Q4-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-10,Q4-2025,2025,TRADE_CREDIT,ExternalCost,210000000,213620919 +2025-10,Q4-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-10,Q4-2025,2025,TRADE_CREDIT,Premium,2100000000,2126102943 +2025-10,Q4-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-10,Q4-2025,2025,TYPHOON_FLOOD,Claims,3876000000,4030161476 +2025-10,Q4-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-10,Q4-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,582263889 +2025-10,Q4-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-10,Q4-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5610645803 +2025-11,Q4-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-11,Q4-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2609023860 +2025-11,Q4-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-11,Q4-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,418999642 +2025-11,Q4-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-11,Q4-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4153368865 +2025-11,Q4-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-11,Q4-2025,2025,CYBER_DIGITAL,Claims,720000000,744211901 +2025-11,Q4-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-11,Q4-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,147548359 +2025-11,Q4-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-11,Q4-2025,2025,CYBER_DIGITAL,Premium,1500000000,1488311452 +2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5534289351 +2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,771962659 +2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-11,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7651383304 +2025-11,Q4-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-11,Q4-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1319662422 +2025-11,Q4-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-11,Q4-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,177614550 +2025-11,Q4-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-11,Q4-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1826233412 +2025-11,Q4-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-11,Q4-2025,2025,MOTOR_TPL,Claims,3330000000,3336574322 +2025-11,Q4-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-11,Q4-2025,2025,MOTOR_TPL,ExternalCost,450000000,462991042 +2025-11,Q4-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-11,Q4-2025,2025,MOTOR_TPL,Premium,4500000000,4525466713 +2025-11,Q4-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-11,Q4-2025,2025,PADDY_CROP,Claims,1560000000,1630416795 +2025-11,Q4-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-11,Q4-2025,2025,PADDY_CROP,ExternalCost,240000000,234460921 +2025-11,Q4-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-11,Q4-2025,2025,PADDY_CROP,Premium,2400000000,2403476710 +2025-11,Q4-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-11,Q4-2025,2025,TRADE_CREDIT,Claims,1155000000,1136849666 +2025-11,Q4-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-11,Q4-2025,2025,TRADE_CREDIT,ExternalCost,210000000,215827932 +2025-11,Q4-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-11,Q4-2025,2025,TRADE_CREDIT,Premium,2100000000,2139513651 +2025-11,Q4-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-11,Q4-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3793333462 +2025-11,Q4-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-11,Q4-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,567762081 +2025-11,Q4-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-11,Q4-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5646526331 +2025-12,Q4-2025,2025,CONSTRUCTION_ENG,CapitalCost,231000000, +2025-12,Q4-2025,2025,CONSTRUCTION_ENG,Claims,2520000000,2507637347 +2025-12,Q4-2025,2025,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2025-12,Q4-2025,2025,CONSTRUCTION_ENG,ExternalCost,420000000,422676463 +2025-12,Q4-2025,2025,CONSTRUCTION_ENG,InternalCost,504000000, +2025-12,Q4-2025,2025,CONSTRUCTION_ENG,Premium,4200000000,4238395570 +2025-12,Q4-2025,2025,CYBER_DIGITAL,CapitalCost,82500000, +2025-12,Q4-2025,2025,CYBER_DIGITAL,Claims,720000000,720587257 +2025-12,Q4-2025,2025,CYBER_DIGITAL,ExpectedProfit,75000000, +2025-12,Q4-2025,2025,CYBER_DIGITAL,ExternalCost,150000000,150689292 +2025-12,Q4-2025,2025,CYBER_DIGITAL,InternalCost,180000000, +2025-12,Q4-2025,2025,CYBER_DIGITAL,Premium,1500000000,1500685384 +2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Claims,5616000000,5765963052 +2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,756679152 +2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2025-12,Q4-2025,2025,EARTHQUAKE_VOLCANIC,Premium,7800000000,7723473422 +2025-12,Q4-2025,2025,MICRO_HEALTH_PA,CapitalCost,99000000, +2025-12,Q4-2025,2025,MICRO_HEALTH_PA,Claims,1260000000,1276475961 +2025-12,Q4-2025,2025,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2025-12,Q4-2025,2025,MICRO_HEALTH_PA,ExternalCost,180000000,182369844 +2025-12,Q4-2025,2025,MICRO_HEALTH_PA,InternalCost,216000000, +2025-12,Q4-2025,2025,MICRO_HEALTH_PA,Premium,1800000000,1830641412 +2025-12,Q4-2025,2025,MOTOR_TPL,CapitalCost,247500000, +2025-12,Q4-2025,2025,MOTOR_TPL,Claims,3330000000,3408755434 +2025-12,Q4-2025,2025,MOTOR_TPL,ExpectedProfit,225000000, +2025-12,Q4-2025,2025,MOTOR_TPL,ExternalCost,450000000,446333980 +2025-12,Q4-2025,2025,MOTOR_TPL,InternalCost,540000000, +2025-12,Q4-2025,2025,MOTOR_TPL,Premium,4500000000,4543551014 +2025-12,Q4-2025,2025,PADDY_CROP,CapitalCost,132000000, +2025-12,Q4-2025,2025,PADDY_CROP,Claims,1560000000,1596096863 +2025-12,Q4-2025,2025,PADDY_CROP,ExpectedProfit,120000000, +2025-12,Q4-2025,2025,PADDY_CROP,ExternalCost,240000000,237554881 +2025-12,Q4-2025,2025,PADDY_CROP,InternalCost,288000000, +2025-12,Q4-2025,2025,PADDY_CROP,Premium,2400000000,2358717486 +2025-12,Q4-2025,2025,TRADE_CREDIT,CapitalCost,115500000, +2025-12,Q4-2025,2025,TRADE_CREDIT,Claims,1155000000,1198706612 +2025-12,Q4-2025,2025,TRADE_CREDIT,ExpectedProfit,105000000, +2025-12,Q4-2025,2025,TRADE_CREDIT,ExternalCost,210000000,212768904 +2025-12,Q4-2025,2025,TRADE_CREDIT,InternalCost,252000000, +2025-12,Q4-2025,2025,TRADE_CREDIT,Premium,2100000000,2084368914 +2025-12,Q4-2025,2025,TYPHOON_FLOOD,CapitalCost,313500000, +2025-12,Q4-2025,2025,TYPHOON_FLOOD,Claims,3876000000,3855622988 +2025-12,Q4-2025,2025,TYPHOON_FLOOD,ExpectedProfit,285000000, +2025-12,Q4-2025,2025,TYPHOON_FLOOD,ExternalCost,570000000,566867037 +2025-12,Q4-2025,2025,TYPHOON_FLOOD,InternalCost,684000000, +2025-12,Q4-2025,2025,TYPHOON_FLOOD,Premium,5700000000,5654473477 +2026-01,Q1-2026,2026,CONSTRUCTION_ENG,CapitalCost,231000000, +2026-01,Q1-2026,2026,CONSTRUCTION_ENG,Claims,2520000000,2504004089 +2026-01,Q1-2026,2026,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2026-01,Q1-2026,2026,CONSTRUCTION_ENG,ExternalCost,420000000,410607653 +2026-01,Q1-2026,2026,CONSTRUCTION_ENG,InternalCost,504000000, +2026-01,Q1-2026,2026,CONSTRUCTION_ENG,Premium,4200000000,4183603265 +2026-01,Q1-2026,2026,CYBER_DIGITAL,CapitalCost,82500000, +2026-01,Q1-2026,2026,CYBER_DIGITAL,Claims,720000000,752564947 +2026-01,Q1-2026,2026,CYBER_DIGITAL,ExpectedProfit,75000000, +2026-01,Q1-2026,2026,CYBER_DIGITAL,ExternalCost,150000000,151595862 +2026-01,Q1-2026,2026,CYBER_DIGITAL,InternalCost,180000000, +2026-01,Q1-2026,2026,CYBER_DIGITAL,Premium,1500000000,1495226780 +2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Claims,5616000000,5724058541 +2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,770684454 +2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2026-01,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Premium,7800000000,7925675330 +2026-01,Q1-2026,2026,MICRO_HEALTH_PA,CapitalCost,99000000, +2026-01,Q1-2026,2026,MICRO_HEALTH_PA,Claims,1260000000,1222240919 +2026-01,Q1-2026,2026,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2026-01,Q1-2026,2026,MICRO_HEALTH_PA,ExternalCost,180000000,177698668 +2026-01,Q1-2026,2026,MICRO_HEALTH_PA,InternalCost,216000000, +2026-01,Q1-2026,2026,MICRO_HEALTH_PA,Premium,1800000000,1803451479 +2026-01,Q1-2026,2026,MOTOR_TPL,CapitalCost,247500000, +2026-01,Q1-2026,2026,MOTOR_TPL,Claims,3330000000,3384607946 +2026-01,Q1-2026,2026,MOTOR_TPL,ExpectedProfit,225000000, +2026-01,Q1-2026,2026,MOTOR_TPL,ExternalCost,450000000,454177052 +2026-01,Q1-2026,2026,MOTOR_TPL,InternalCost,540000000, +2026-01,Q1-2026,2026,MOTOR_TPL,Premium,4500000000,4487379867 +2026-01,Q1-2026,2026,PADDY_CROP,CapitalCost,132000000, +2026-01,Q1-2026,2026,PADDY_CROP,Claims,1560000000,1568381543 +2026-01,Q1-2026,2026,PADDY_CROP,ExpectedProfit,120000000, +2026-01,Q1-2026,2026,PADDY_CROP,ExternalCost,240000000,235877300 +2026-01,Q1-2026,2026,PADDY_CROP,InternalCost,288000000, +2026-01,Q1-2026,2026,PADDY_CROP,Premium,2400000000,2396638866 +2026-01,Q1-2026,2026,TRADE_CREDIT,CapitalCost,115500000, +2026-01,Q1-2026,2026,TRADE_CREDIT,Claims,1155000000,1203619108 +2026-01,Q1-2026,2026,TRADE_CREDIT,ExpectedProfit,105000000, +2026-01,Q1-2026,2026,TRADE_CREDIT,ExternalCost,210000000,213729912 +2026-01,Q1-2026,2026,TRADE_CREDIT,InternalCost,252000000, +2026-01,Q1-2026,2026,TRADE_CREDIT,Premium,2100000000,2097747640 +2026-01,Q1-2026,2026,TYPHOON_FLOOD,CapitalCost,313500000, +2026-01,Q1-2026,2026,TYPHOON_FLOOD,Claims,3876000000,3786013400 +2026-01,Q1-2026,2026,TYPHOON_FLOOD,ExpectedProfit,285000000, +2026-01,Q1-2026,2026,TYPHOON_FLOOD,ExternalCost,570000000,570528459 +2026-01,Q1-2026,2026,TYPHOON_FLOOD,InternalCost,684000000, +2026-01,Q1-2026,2026,TYPHOON_FLOOD,Premium,5700000000,5624689638 +2026-02,Q1-2026,2026,CONSTRUCTION_ENG,CapitalCost,231000000, +2026-02,Q1-2026,2026,CONSTRUCTION_ENG,Claims,2520000000,2511973952 +2026-02,Q1-2026,2026,CONSTRUCTION_ENG,ExpectedProfit,210000000, +2026-02,Q1-2026,2026,CONSTRUCTION_ENG,ExternalCost,420000000,428024271 +2026-02,Q1-2026,2026,CONSTRUCTION_ENG,InternalCost,504000000, +2026-02,Q1-2026,2026,CONSTRUCTION_ENG,Premium,4200000000,4222334064 +2026-02,Q1-2026,2026,CYBER_DIGITAL,CapitalCost,82500000, +2026-02,Q1-2026,2026,CYBER_DIGITAL,Claims,720000000,737153031 +2026-02,Q1-2026,2026,CYBER_DIGITAL,ExpectedProfit,75000000, +2026-02,Q1-2026,2026,CYBER_DIGITAL,ExternalCost,150000000,147521766 +2026-02,Q1-2026,2026,CYBER_DIGITAL,InternalCost,180000000, +2026-02,Q1-2026,2026,CYBER_DIGITAL,Premium,1500000000,1515068288 +2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,CapitalCost,429000000, +2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Claims,5616000000,5458493838 +2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExpectedProfit,390000000, +2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,ExternalCost,780000000,768058631 +2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,InternalCost,936000000, +2026-02,Q1-2026,2026,EARTHQUAKE_VOLCANIC,Premium,7800000000,7706128539 +2026-02,Q1-2026,2026,MICRO_HEALTH_PA,CapitalCost,99000000, +2026-02,Q1-2026,2026,MICRO_HEALTH_PA,Claims,1260000000,1307853560 +2026-02,Q1-2026,2026,MICRO_HEALTH_PA,ExpectedProfit,90000000, +2026-02,Q1-2026,2026,MICRO_HEALTH_PA,ExternalCost,180000000,175386545 +2026-02,Q1-2026,2026,MICRO_HEALTH_PA,InternalCost,216000000, +2026-02,Q1-2026,2026,MICRO_HEALTH_PA,Premium,1800000000,1798209817 +2026-02,Q1-2026,2026,MOTOR_TPL,CapitalCost,247500000, +2026-02,Q1-2026,2026,MOTOR_TPL,Claims,3330000000,3397869497 +2026-02,Q1-2026,2026,MOTOR_TPL,ExpectedProfit,225000000, +2026-02,Q1-2026,2026,MOTOR_TPL,ExternalCost,450000000,441749751 +2026-02,Q1-2026,2026,MOTOR_TPL,InternalCost,540000000, +2026-02,Q1-2026,2026,MOTOR_TPL,Premium,4500000000,4484599382 +2026-02,Q1-2026,2026,PADDY_CROP,CapitalCost,132000000, +2026-02,Q1-2026,2026,PADDY_CROP,Claims,1560000000,1574898271 +2026-02,Q1-2026,2026,PADDY_CROP,ExpectedProfit,120000000, +2026-02,Q1-2026,2026,PADDY_CROP,ExternalCost,240000000,236313376 +2026-02,Q1-2026,2026,PADDY_CROP,InternalCost,288000000, +2026-02,Q1-2026,2026,PADDY_CROP,Premium,2400000000,2418850008 +2026-02,Q1-2026,2026,TRADE_CREDIT,CapitalCost,115500000, +2026-02,Q1-2026,2026,TRADE_CREDIT,Claims,1155000000,1120862341 +2026-02,Q1-2026,2026,TRADE_CREDIT,ExpectedProfit,105000000, +2026-02,Q1-2026,2026,TRADE_CREDIT,ExternalCost,210000000,213162152 +2026-02,Q1-2026,2026,TRADE_CREDIT,InternalCost,252000000, +2026-02,Q1-2026,2026,TRADE_CREDIT,Premium,2100000000,2113108873 +2026-02,Q1-2026,2026,TYPHOON_FLOOD,CapitalCost,313500000, +2026-02,Q1-2026,2026,TYPHOON_FLOOD,Claims,3876000000,3792770589 +2026-02,Q1-2026,2026,TYPHOON_FLOOD,ExpectedProfit,285000000, +2026-02,Q1-2026,2026,TYPHOON_FLOOD,ExternalCost,570000000,567440000 +2026-02,Q1-2026,2026,TYPHOON_FLOOD,InternalCost,684000000, +2026-02,Q1-2026,2026,TYPHOON_FLOOD,Premium,5700000000,5761570531 diff --git a/samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv b/samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv new file mode 100644 index 000000000..59edc7ef2 --- /dev/null +++ b/samples/Graph/attachments/FutuRe/EuropeRe/Analysis/datacube.csv @@ -0,0 +1,865 @@ +Month,Quarter,Year,LineOfBusiness,AmountType,Estimate,Actual +2024-09,Q3-2024,2024,COMM_FIRE,CapitalCost,2475000, +2024-09,Q3-2024,2024,COMM_FIRE,Claims,30760000,31375200 +2024-09,Q3-2024,2024,COMM_FIRE,ExpectedProfit,2250000, +2024-09,Q3-2024,2024,COMM_FIRE,ExternalCost,4500000,4590000 +2024-09,Q3-2024,2024,COMM_FIRE,InternalCost,5400000, +2024-09,Q3-2024,2024,COMM_FIRE,Premium,45000000,45900000 +2024-09,Q3-2024,2024,HOUSEHOLD,CapitalCost,4125000, +2024-09,Q3-2024,2024,HOUSEHOLD,Claims,56568065,57699426 +2024-09,Q3-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, +2024-09,Q3-2024,2024,HOUSEHOLD,ExternalCost,7500000,7650000 +2024-09,Q3-2024,2024,HOUSEHOLD,InternalCost,9000000, +2024-09,Q3-2024,2024,HOUSEHOLD,Premium,78750000,80325000 +2024-09,Q3-2024,2024,LIABILITY,CapitalCost,2090000, +2024-09,Q3-2024,2024,LIABILITY,Claims,23940000,24418800 +2024-09,Q3-2024,2024,LIABILITY,ExpectedProfit,1900000, +2024-09,Q3-2024,2024,LIABILITY,ExternalCost,3800000,3876000 +2024-09,Q3-2024,2024,LIABILITY,InternalCost,4560000, +2024-09,Q3-2024,2024,LIABILITY,Premium,38000000,38760000 +2024-09,Q3-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, +2024-09,Q3-2024,2024,LIFE_HEALTH_EU,Claims,27840000,28396800 +2024-09,Q3-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2024-09,Q3-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,4896000 +2024-09,Q3-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, +2024-09,Q3-2024,2024,LIFE_HEALTH_EU,Premium,48000000,48960000 +2024-09,Q3-2024,2024,MOTOR,CapitalCost,3025000, +2024-09,Q3-2024,2024,MOTOR,Claims,40577778,41389334 +2024-09,Q3-2024,2024,MOTOR,ExpectedProfit,2750000, +2024-09,Q3-2024,2024,MOTOR,ExternalCost,5500000,5610000 +2024-09,Q3-2024,2024,MOTOR,InternalCost,6600000, +2024-09,Q3-2024,2024,MOTOR,Premium,55000000,56100000 +2024-09,Q3-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, +2024-09,Q3-2024,2024,SPECIALTY_AVTN,Claims,15750000,16065000 +2024-09,Q3-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, +2024-09,Q3-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2550000 +2024-09,Q3-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, +2024-09,Q3-2024,2024,SPECIALTY_AVTN,Premium,25000000,25500000 +2024-09,Q3-2024,2024,TECH_RISK,CapitalCost,1760000, +2024-09,Q3-2024,2024,TECH_RISK,Claims,15273244,15578709 +2024-09,Q3-2024,2024,TECH_RISK,ExpectedProfit,1600000, +2024-09,Q3-2024,2024,TECH_RISK,ExternalCost,3200000,3264000 +2024-09,Q3-2024,2024,TECH_RISK,InternalCost,3840000, +2024-09,Q3-2024,2024,TECH_RISK,Premium,32000000,32640000 +2024-09,Q3-2024,2024,TRANSPORT,CapitalCost,1210000, +2024-09,Q3-2024,2024,TRANSPORT,Claims,14774222,15069706 +2024-09,Q3-2024,2024,TRANSPORT,ExpectedProfit,1100000, +2024-09,Q3-2024,2024,TRANSPORT,ExternalCost,2200000,2244000 +2024-09,Q3-2024,2024,TRANSPORT,InternalCost,2640000, +2024-09,Q3-2024,2024,TRANSPORT,Premium,22000000,22440000 +2024-10,Q4-2024,2024,COMM_FIRE,CapitalCost,2475000, +2024-10,Q4-2024,2024,COMM_FIRE,Claims,27250000,26432500 +2024-10,Q4-2024,2024,COMM_FIRE,ExpectedProfit,2250000, +2024-10,Q4-2024,2024,COMM_FIRE,ExternalCost,4500000,4365000 +2024-10,Q4-2024,2024,COMM_FIRE,InternalCost,5400000, +2024-10,Q4-2024,2024,COMM_FIRE,Premium,45000000,43650000 +2024-10,Q4-2024,2024,HOUSEHOLD,CapitalCost,4125000, +2024-10,Q4-2024,2024,HOUSEHOLD,Claims,52717205,51135689 +2024-10,Q4-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, +2024-10,Q4-2024,2024,HOUSEHOLD,ExternalCost,7500000,7275000 +2024-10,Q4-2024,2024,HOUSEHOLD,InternalCost,9000000, +2024-10,Q4-2024,2024,HOUSEHOLD,Premium,75000000,72750000 +2024-10,Q4-2024,2024,LIABILITY,CapitalCost,2090000, +2024-10,Q4-2024,2024,LIABILITY,Claims,23940000,23221800 +2024-10,Q4-2024,2024,LIABILITY,ExpectedProfit,1900000, +2024-10,Q4-2024,2024,LIABILITY,ExternalCost,3800000,3686000 +2024-10,Q4-2024,2024,LIABILITY,InternalCost,4560000, +2024-10,Q4-2024,2024,LIABILITY,Premium,38000000,36860000 +2024-10,Q4-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, +2024-10,Q4-2024,2024,LIFE_HEALTH_EU,Claims,27840000,27004800 +2024-10,Q4-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2024-10,Q4-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,4656000 +2024-10,Q4-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, +2024-10,Q4-2024,2024,LIFE_HEALTH_EU,Premium,48000000,46560000 +2024-10,Q4-2024,2024,MOTOR,CapitalCost,3025000, +2024-10,Q4-2024,2024,MOTOR,Claims,39081778,37909325 +2024-10,Q4-2024,2024,MOTOR,ExpectedProfit,2750000, +2024-10,Q4-2024,2024,MOTOR,ExternalCost,5500000,5335000 +2024-10,Q4-2024,2024,MOTOR,InternalCost,6600000, +2024-10,Q4-2024,2024,MOTOR,Premium,55000000,53350000 +2024-10,Q4-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, +2024-10,Q4-2024,2024,SPECIALTY_AVTN,Claims,15750000,15277500 +2024-10,Q4-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, +2024-10,Q4-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2425000 +2024-10,Q4-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, +2024-10,Q4-2024,2024,SPECIALTY_AVTN,Premium,25000000,24250000 +2024-10,Q4-2024,2024,TECH_RISK,CapitalCost,1760000, +2024-10,Q4-2024,2024,TECH_RISK,Claims,16860444,16354631 +2024-10,Q4-2024,2024,TECH_RISK,ExpectedProfit,1600000, +2024-10,Q4-2024,2024,TECH_RISK,ExternalCost,3200000,3104000 +2024-10,Q4-2024,2024,TECH_RISK,InternalCost,3840000, +2024-10,Q4-2024,2024,TECH_RISK,Premium,32000000,31040000 +2024-10,Q4-2024,2024,TRANSPORT,CapitalCost,1210000, +2024-10,Q4-2024,2024,TRANSPORT,Claims,15390222,14928515 +2024-10,Q4-2024,2024,TRANSPORT,ExpectedProfit,1100000, +2024-10,Q4-2024,2024,TRANSPORT,ExternalCost,2200000,2134000 +2024-10,Q4-2024,2024,TRANSPORT,InternalCost,2640000, +2024-10,Q4-2024,2024,TRANSPORT,Premium,22000000,21340000 +2024-11,Q4-2024,2024,COMM_FIRE,CapitalCost,2475000, +2024-11,Q4-2024,2024,COMM_FIRE,Claims,26080000,27384000 +2024-11,Q4-2024,2024,COMM_FIRE,ExpectedProfit,2250000, +2024-11,Q4-2024,2024,COMM_FIRE,ExternalCost,4500000,4725000 +2024-11,Q4-2024,2024,COMM_FIRE,InternalCost,5400000, +2024-11,Q4-2024,2024,COMM_FIRE,Premium,45000000,47250000 +2024-11,Q4-2024,2024,HOUSEHOLD,CapitalCost,4125000, +2024-11,Q4-2024,2024,HOUSEHOLD,Claims,47246345,49608662 +2024-11,Q4-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, +2024-11,Q4-2024,2024,HOUSEHOLD,ExternalCost,7500000,7875000 +2024-11,Q4-2024,2024,HOUSEHOLD,InternalCost,9000000, +2024-11,Q4-2024,2024,HOUSEHOLD,Premium,71250000,74812500 +2024-11,Q4-2024,2024,LIABILITY,CapitalCost,2090000, +2024-11,Q4-2024,2024,LIABILITY,Claims,23940000,25137000 +2024-11,Q4-2024,2024,LIABILITY,ExpectedProfit,1900000, +2024-11,Q4-2024,2024,LIABILITY,ExternalCost,3800000,3990000 +2024-11,Q4-2024,2024,LIABILITY,InternalCost,4560000, +2024-11,Q4-2024,2024,LIABILITY,Premium,38000000,39900000 +2024-11,Q4-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, +2024-11,Q4-2024,2024,LIFE_HEALTH_EU,Claims,27840000,29232000 +2024-11,Q4-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2024-11,Q4-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,5040000 +2024-11,Q4-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, +2024-11,Q4-2024,2024,LIFE_HEALTH_EU,Premium,48000000,50400000 +2024-11,Q4-2024,2024,MOTOR,CapitalCost,3025000, +2024-11,Q4-2024,2024,MOTOR,Claims,37585778,39465067 +2024-11,Q4-2024,2024,MOTOR,ExpectedProfit,2750000, +2024-11,Q4-2024,2024,MOTOR,ExternalCost,5500000,5775000 +2024-11,Q4-2024,2024,MOTOR,InternalCost,6600000, +2024-11,Q4-2024,2024,MOTOR,Premium,55000000,57750000 +2024-11,Q4-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, +2024-11,Q4-2024,2024,SPECIALTY_AVTN,Claims,15750000,16537500 +2024-11,Q4-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, +2024-11,Q4-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2625000 +2024-11,Q4-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, +2024-11,Q4-2024,2024,SPECIALTY_AVTN,Premium,25000000,26250000 +2024-11,Q4-2024,2024,TECH_RISK,CapitalCost,1760000, +2024-11,Q4-2024,2024,TECH_RISK,Claims,17654044,18536746 +2024-11,Q4-2024,2024,TECH_RISK,ExpectedProfit,1600000, +2024-11,Q4-2024,2024,TECH_RISK,ExternalCost,3200000,3360000 +2024-11,Q4-2024,2024,TECH_RISK,InternalCost,3840000, +2024-11,Q4-2024,2024,TECH_RISK,Premium,32000000,33600000 +2024-11,Q4-2024,2024,TRANSPORT,CapitalCost,1210000, +2024-11,Q4-2024,2024,TRANSPORT,Claims,16006222,16806533 +2024-11,Q4-2024,2024,TRANSPORT,ExpectedProfit,1100000, +2024-11,Q4-2024,2024,TRANSPORT,ExternalCost,2200000,2310000 +2024-11,Q4-2024,2024,TRANSPORT,InternalCost,2640000, +2024-11,Q4-2024,2024,TRANSPORT,Premium,22000000,23100000 +2024-12,Q4-2024,2024,COMM_FIRE,CapitalCost,2475000, +2024-12,Q4-2024,2024,COMM_FIRE,Claims,28420000,27851600 +2024-12,Q4-2024,2024,COMM_FIRE,ExpectedProfit,2250000, +2024-12,Q4-2024,2024,COMM_FIRE,ExternalCost,4500000,4410000 +2024-12,Q4-2024,2024,COMM_FIRE,InternalCost,5400000, +2024-12,Q4-2024,2024,COMM_FIRE,Premium,45000000,44100000 +2024-12,Q4-2024,2024,HOUSEHOLD,CapitalCost,4125000, +2024-12,Q4-2024,2024,HOUSEHOLD,Claims,48255484,47290374 +2024-12,Q4-2024,2024,HOUSEHOLD,ExpectedProfit,3750000, +2024-12,Q4-2024,2024,HOUSEHOLD,ExternalCost,7500000,7350000 +2024-12,Q4-2024,2024,HOUSEHOLD,InternalCost,9000000, +2024-12,Q4-2024,2024,HOUSEHOLD,Premium,67500000,66150000 +2024-12,Q4-2024,2024,LIABILITY,CapitalCost,2090000, +2024-12,Q4-2024,2024,LIABILITY,Claims,23940000,23461200 +2024-12,Q4-2024,2024,LIABILITY,ExpectedProfit,1900000, +2024-12,Q4-2024,2024,LIABILITY,ExternalCost,3800000,3724000 +2024-12,Q4-2024,2024,LIABILITY,InternalCost,4560000, +2024-12,Q4-2024,2024,LIABILITY,Premium,38000000,37240000 +2024-12,Q4-2024,2024,LIFE_HEALTH_EU,CapitalCost,2640000, +2024-12,Q4-2024,2024,LIFE_HEALTH_EU,Claims,27840000,27283200 +2024-12,Q4-2024,2024,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2024-12,Q4-2024,2024,LIFE_HEALTH_EU,ExternalCost,4800000,4704000 +2024-12,Q4-2024,2024,LIFE_HEALTH_EU,InternalCost,5760000, +2024-12,Q4-2024,2024,LIFE_HEALTH_EU,Premium,48000000,47040000 +2024-12,Q4-2024,2024,MOTOR,CapitalCost,3025000, +2024-12,Q4-2024,2024,MOTOR,Claims,36089778,35367982 +2024-12,Q4-2024,2024,MOTOR,ExpectedProfit,2750000, +2024-12,Q4-2024,2024,MOTOR,ExternalCost,5500000,5390000 +2024-12,Q4-2024,2024,MOTOR,InternalCost,6600000, +2024-12,Q4-2024,2024,MOTOR,Premium,55000000,53900000 +2024-12,Q4-2024,2024,SPECIALTY_AVTN,CapitalCost,1375000, +2024-12,Q4-2024,2024,SPECIALTY_AVTN,Claims,15750000,15435000 +2024-12,Q4-2024,2024,SPECIALTY_AVTN,ExpectedProfit,1250000, +2024-12,Q4-2024,2024,SPECIALTY_AVTN,ExternalCost,2500000,2450000 +2024-12,Q4-2024,2024,SPECIALTY_AVTN,InternalCost,3000000, +2024-12,Q4-2024,2024,SPECIALTY_AVTN,Premium,25000000,24500000 +2024-12,Q4-2024,2024,TECH_RISK,CapitalCost,1760000, +2024-12,Q4-2024,2024,TECH_RISK,Claims,20034844,19634147 +2024-12,Q4-2024,2024,TECH_RISK,ExpectedProfit,1600000, +2024-12,Q4-2024,2024,TECH_RISK,ExternalCost,3200000,3136000 +2024-12,Q4-2024,2024,TECH_RISK,InternalCost,3840000, +2024-12,Q4-2024,2024,TECH_RISK,Premium,32000000,31360000 +2024-12,Q4-2024,2024,TRANSPORT,CapitalCost,1210000, +2024-12,Q4-2024,2024,TRANSPORT,Claims,16622222,16289778 +2024-12,Q4-2024,2024,TRANSPORT,ExpectedProfit,1100000, +2024-12,Q4-2024,2024,TRANSPORT,ExternalCost,2200000,2156000 +2024-12,Q4-2024,2024,TRANSPORT,InternalCost,2640000, +2024-12,Q4-2024,2024,TRANSPORT,Premium,22000000,21560000 +2025-01,Q1-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-01,Q1-2025,2025,COMM_FIRE,Claims,28420000,28704200 +2025-01,Q1-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-01,Q1-2025,2025,COMM_FIRE,ExternalCost,4500000,4545000 +2025-01,Q1-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-01,Q1-2025,2025,COMM_FIRE,Premium,45000000,45450000 +2025-01,Q1-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-01,Q1-2025,2025,HOUSEHOLD,Claims,48866345,49355008 +2025-01,Q1-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-01,Q1-2025,2025,HOUSEHOLD,ExternalCost,7500000,7575000 +2025-01,Q1-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-01,Q1-2025,2025,HOUSEHOLD,Premium,71250000,71962500 +2025-01,Q1-2025,2025,LIABILITY,CapitalCost,2090000, +2025-01,Q1-2025,2025,LIABILITY,Claims,23940000,24179400 +2025-01,Q1-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-01,Q1-2025,2025,LIABILITY,ExternalCost,3800000,3838000 +2025-01,Q1-2025,2025,LIABILITY,InternalCost,4560000, +2025-01,Q1-2025,2025,LIABILITY,Premium,38000000,38380000 +2025-01,Q1-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-01,Q1-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28118400 +2025-01,Q1-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-01,Q1-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4848000 +2025-01,Q1-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-01,Q1-2025,2025,LIFE_HEALTH_EU,Premium,48000000,48480000 +2025-01,Q1-2025,2025,MOTOR,CapitalCost,3025000, +2025-01,Q1-2025,2025,MOTOR,Claims,36089778,36450676 +2025-01,Q1-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-01,Q1-2025,2025,MOTOR,ExternalCost,5500000,5555000 +2025-01,Q1-2025,2025,MOTOR,InternalCost,6600000, +2025-01,Q1-2025,2025,MOTOR,Premium,55000000,55550000 +2025-01,Q1-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-01,Q1-2025,2025,SPECIALTY_AVTN,Claims,15750000,15907500 +2025-01,Q1-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-01,Q1-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2525000 +2025-01,Q1-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-01,Q1-2025,2025,SPECIALTY_AVTN,Premium,25000000,25250000 +2025-01,Q1-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-01,Q1-2025,2025,TECH_RISK,Claims,18447644,18632120 +2025-01,Q1-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-01,Q1-2025,2025,TECH_RISK,ExternalCost,3200000,3232000 +2025-01,Q1-2025,2025,TECH_RISK,InternalCost,3840000, +2025-01,Q1-2025,2025,TECH_RISK,Premium,32000000,32320000 +2025-01,Q1-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-01,Q1-2025,2025,TRANSPORT,Claims,15390222,15544124 +2025-01,Q1-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-01,Q1-2025,2025,TRANSPORT,ExternalCost,2200000,2222000 +2025-01,Q1-2025,2025,TRANSPORT,InternalCost,2640000, +2025-01,Q1-2025,2025,TRANSPORT,Premium,22000000,22220000 +2025-02,Q1-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-02,Q1-2025,2025,COMM_FIRE,Claims,27250000,26160000 +2025-02,Q1-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-02,Q1-2025,2025,COMM_FIRE,ExternalCost,4500000,4320000 +2025-02,Q1-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-02,Q1-2025,2025,COMM_FIRE,Premium,45000000,43200000 +2025-02,Q1-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-02,Q1-2025,2025,HOUSEHOLD,Claims,46879829,45004636 +2025-02,Q1-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-02,Q1-2025,2025,HOUSEHOLD,ExternalCost,7500000,7200000 +2025-02,Q1-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-02,Q1-2025,2025,HOUSEHOLD,Premium,69000000,66240000 +2025-02,Q1-2025,2025,LIABILITY,CapitalCost,2090000, +2025-02,Q1-2025,2025,LIABILITY,Claims,23940000,22982400 +2025-02,Q1-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-02,Q1-2025,2025,LIABILITY,ExternalCost,3800000,3648000 +2025-02,Q1-2025,2025,LIABILITY,InternalCost,4560000, +2025-02,Q1-2025,2025,LIABILITY,Premium,38000000,36480000 +2025-02,Q1-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-02,Q1-2025,2025,LIFE_HEALTH_EU,Claims,27840000,26726400 +2025-02,Q1-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-02,Q1-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4608000 +2025-02,Q1-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-02,Q1-2025,2025,LIFE_HEALTH_EU,Premium,48000000,46080000 +2025-02,Q1-2025,2025,MOTOR,CapitalCost,3025000, +2025-02,Q1-2025,2025,MOTOR,Claims,34593778,33210027 +2025-02,Q1-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-02,Q1-2025,2025,MOTOR,ExternalCost,5500000,5280000 +2025-02,Q1-2025,2025,MOTOR,InternalCost,6600000, +2025-02,Q1-2025,2025,MOTOR,Premium,55000000,52800000 +2025-02,Q1-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-02,Q1-2025,2025,SPECIALTY_AVTN,Claims,15750000,15120000 +2025-02,Q1-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-02,Q1-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2400000 +2025-02,Q1-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-02,Q1-2025,2025,SPECIALTY_AVTN,Premium,25000000,24000000 +2025-02,Q1-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-02,Q1-2025,2025,TECH_RISK,Claims,16860444,16186026 +2025-02,Q1-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-02,Q1-2025,2025,TECH_RISK,ExternalCost,3200000,3072000 +2025-02,Q1-2025,2025,TECH_RISK,InternalCost,3840000, +2025-02,Q1-2025,2025,TECH_RISK,Premium,32000000,30720000 +2025-02,Q1-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-02,Q1-2025,2025,TRANSPORT,Claims,14774222,14183253 +2025-02,Q1-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-02,Q1-2025,2025,TRANSPORT,ExternalCost,2200000,2112000 +2025-02,Q1-2025,2025,TRANSPORT,InternalCost,2640000, +2025-02,Q1-2025,2025,TRANSPORT,Premium,22000000,21120000 +2025-03,Q1-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-03,Q1-2025,2025,COMM_FIRE,Claims,24910000,25657300 +2025-03,Q1-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-03,Q1-2025,2025,COMM_FIRE,ExternalCost,4500000,4635000 +2025-03,Q1-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-03,Q1-2025,2025,COMM_FIRE,Premium,45000000,46350000 +2025-03,Q1-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-03,Q1-2025,2025,HOUSEHOLD,Claims,42997205,44287121 +2025-03,Q1-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-03,Q1-2025,2025,HOUSEHOLD,ExternalCost,7500000,7725000 +2025-03,Q1-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-03,Q1-2025,2025,HOUSEHOLD,Premium,75000000,77250000 +2025-03,Q1-2025,2025,LIABILITY,CapitalCost,2090000, +2025-03,Q1-2025,2025,LIABILITY,Claims,23940000,24658200 +2025-03,Q1-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-03,Q1-2025,2025,LIABILITY,ExternalCost,3800000,3914000 +2025-03,Q1-2025,2025,LIABILITY,InternalCost,4560000, +2025-03,Q1-2025,2025,LIABILITY,Premium,38000000,39140000 +2025-03,Q1-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-03,Q1-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28675200 +2025-03,Q1-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-03,Q1-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4944000 +2025-03,Q1-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-03,Q1-2025,2025,LIFE_HEALTH_EU,Premium,48000000,49440000 +2025-03,Q1-2025,2025,MOTOR,CapitalCost,3025000, +2025-03,Q1-2025,2025,MOTOR,Claims,37585778,38713351 +2025-03,Q1-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-03,Q1-2025,2025,MOTOR,ExternalCost,5500000,5665000 +2025-03,Q1-2025,2025,MOTOR,InternalCost,6600000, +2025-03,Q1-2025,2025,MOTOR,Premium,55000000,56650000 +2025-03,Q1-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-03,Q1-2025,2025,SPECIALTY_AVTN,Claims,15750000,16222500 +2025-03,Q1-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-03,Q1-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2575000 +2025-03,Q1-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-03,Q1-2025,2025,SPECIALTY_AVTN,Premium,25000000,25750000 +2025-03,Q1-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-03,Q1-2025,2025,TECH_RISK,Claims,15273244,15731441 +2025-03,Q1-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-03,Q1-2025,2025,TECH_RISK,ExternalCost,3200000,3296000 +2025-03,Q1-2025,2025,TECH_RISK,InternalCost,3840000, +2025-03,Q1-2025,2025,TECH_RISK,Premium,32000000,32960000 +2025-03,Q1-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-03,Q1-2025,2025,TRANSPORT,Claims,13542222,13948489 +2025-03,Q1-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-03,Q1-2025,2025,TRANSPORT,ExternalCost,2200000,2266000 +2025-03,Q1-2025,2025,TRANSPORT,InternalCost,2640000, +2025-03,Q1-2025,2025,TRANSPORT,Premium,22000000,22660000 +2025-04,Q2-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-04,Q2-2025,2025,COMM_FIRE,Claims,23740000,23502600 +2025-04,Q2-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-04,Q2-2025,2025,COMM_FIRE,ExternalCost,4500000,4455000 +2025-04,Q2-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-04,Q2-2025,2025,COMM_FIRE,Premium,45000000,44550000 +2025-04,Q2-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-04,Q2-2025,2025,HOUSEHOLD,Claims,41621549,41205334 +2025-04,Q2-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-04,Q2-2025,2025,HOUSEHOLD,ExternalCost,7500000,7425000 +2025-04,Q2-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-04,Q2-2025,2025,HOUSEHOLD,Premium,76500000,75735000 +2025-04,Q2-2025,2025,LIABILITY,CapitalCost,2090000, +2025-04,Q2-2025,2025,LIABILITY,Claims,23940000,23700600 +2025-04,Q2-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-04,Q2-2025,2025,LIABILITY,ExternalCost,3800000,3762000 +2025-04,Q2-2025,2025,LIABILITY,InternalCost,4560000, +2025-04,Q2-2025,2025,LIABILITY,Premium,38000000,37620000 +2025-04,Q2-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-04,Q2-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27561600 +2025-04,Q2-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-04,Q2-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4752000 +2025-04,Q2-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-04,Q2-2025,2025,LIFE_HEALTH_EU,Premium,48000000,47520000 +2025-04,Q2-2025,2025,MOTOR,CapitalCost,3025000, +2025-04,Q2-2025,2025,MOTOR,Claims,39081778,38690960 +2025-04,Q2-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-04,Q2-2025,2025,MOTOR,ExternalCost,5500000,5445000 +2025-04,Q2-2025,2025,MOTOR,InternalCost,6600000, +2025-04,Q2-2025,2025,MOTOR,Premium,55000000,54450000 +2025-04,Q2-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-04,Q2-2025,2025,SPECIALTY_AVTN,Claims,15750000,15592500 +2025-04,Q2-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-04,Q2-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2475000 +2025-04,Q2-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-04,Q2-2025,2025,SPECIALTY_AVTN,Premium,25000000,24750000 +2025-04,Q2-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-04,Q2-2025,2025,TECH_RISK,Claims,13686044,13549184 +2025-04,Q2-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-04,Q2-2025,2025,TECH_RISK,ExternalCost,3200000,3168000 +2025-04,Q2-2025,2025,TECH_RISK,InternalCost,3840000, +2025-04,Q2-2025,2025,TECH_RISK,Premium,32000000,31680000 +2025-04,Q2-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-04,Q2-2025,2025,TRANSPORT,Claims,12926222,12796960 +2025-04,Q2-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-04,Q2-2025,2025,TRANSPORT,ExternalCost,2200000,2178000 +2025-04,Q2-2025,2025,TRANSPORT,InternalCost,2640000, +2025-04,Q2-2025,2025,TRANSPORT,Premium,22000000,21780000 +2025-05,Q2-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-05,Q2-2025,2025,COMM_FIRE,Claims,24910000,25906400 +2025-05,Q2-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-05,Q2-2025,2025,COMM_FIRE,ExternalCost,4500000,4680000 +2025-05,Q2-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-05,Q2-2025,2025,COMM_FIRE,Premium,45000000,46800000 +2025-05,Q2-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-05,Q2-2025,2025,HOUSEHOLD,Claims,40368065,41982788 +2025-05,Q2-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-05,Q2-2025,2025,HOUSEHOLD,ExternalCost,7500000,7800000 +2025-05,Q2-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-05,Q2-2025,2025,HOUSEHOLD,Premium,78750000,81900000 +2025-05,Q2-2025,2025,LIABILITY,CapitalCost,2090000, +2025-05,Q2-2025,2025,LIABILITY,Claims,23940000,24897600 +2025-05,Q2-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-05,Q2-2025,2025,LIABILITY,ExternalCost,3800000,3952000 +2025-05,Q2-2025,2025,LIABILITY,InternalCost,4560000, +2025-05,Q2-2025,2025,LIABILITY,Premium,38000000,39520000 +2025-05,Q2-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-05,Q2-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28953600 +2025-05,Q2-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-05,Q2-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4992000 +2025-05,Q2-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-05,Q2-2025,2025,LIFE_HEALTH_EU,Premium,48000000,49920000 +2025-05,Q2-2025,2025,MOTOR,CapitalCost,3025000, +2025-05,Q2-2025,2025,MOTOR,Claims,40577778,42200889 +2025-05,Q2-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-05,Q2-2025,2025,MOTOR,ExternalCost,5500000,5720000 +2025-05,Q2-2025,2025,MOTOR,InternalCost,6600000, +2025-05,Q2-2025,2025,MOTOR,Premium,55000000,57200000 +2025-05,Q2-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-05,Q2-2025,2025,SPECIALTY_AVTN,Claims,15750000,16380000 +2025-05,Q2-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-05,Q2-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2600000 +2025-05,Q2-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-05,Q2-2025,2025,SPECIALTY_AVTN,Premium,25000000,26000000 +2025-05,Q2-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-05,Q2-2025,2025,TECH_RISK,Claims,14479644,15058830 +2025-05,Q2-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-05,Q2-2025,2025,TECH_RISK,ExternalCost,3200000,3328000 +2025-05,Q2-2025,2025,TECH_RISK,InternalCost,3840000, +2025-05,Q2-2025,2025,TECH_RISK,Premium,32000000,33280000 +2025-05,Q2-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-05,Q2-2025,2025,TRANSPORT,Claims,12310222,12802631 +2025-05,Q2-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-05,Q2-2025,2025,TRANSPORT,ExternalCost,2200000,2288000 +2025-05,Q2-2025,2025,TRANSPORT,InternalCost,2640000, +2025-05,Q2-2025,2025,TRANSPORT,Premium,22000000,22880000 +2025-06,Q2-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-06,Q2-2025,2025,COMM_FIRE,Claims,29590000,28110500 +2025-06,Q2-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-06,Q2-2025,2025,COMM_FIRE,ExternalCost,4500000,4275000 +2025-06,Q2-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-06,Q2-2025,2025,COMM_FIRE,Premium,45000000,42750000 +2025-06,Q2-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-06,Q2-2025,2025,HOUSEHOLD,Claims,42354581,40236852 +2025-06,Q2-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-06,Q2-2025,2025,HOUSEHOLD,ExternalCost,7500000,7125000 +2025-06,Q2-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-06,Q2-2025,2025,HOUSEHOLD,Premium,81000000,76950000 +2025-06,Q2-2025,2025,LIABILITY,CapitalCost,2090000, +2025-06,Q2-2025,2025,LIABILITY,Claims,23940000,22743000 +2025-06,Q2-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-06,Q2-2025,2025,LIABILITY,ExternalCost,3800000,3610000 +2025-06,Q2-2025,2025,LIABILITY,InternalCost,4560000, +2025-06,Q2-2025,2025,LIABILITY,Premium,38000000,36100000 +2025-06,Q2-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-06,Q2-2025,2025,LIFE_HEALTH_EU,Claims,27840000,26448000 +2025-06,Q2-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-06,Q2-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4560000 +2025-06,Q2-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-06,Q2-2025,2025,LIFE_HEALTH_EU,Premium,48000000,45600000 +2025-06,Q2-2025,2025,MOTOR,CapitalCost,3025000, +2025-06,Q2-2025,2025,MOTOR,Claims,42073778,39970089 +2025-06,Q2-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-06,Q2-2025,2025,MOTOR,ExternalCost,5500000,5225000 +2025-06,Q2-2025,2025,MOTOR,InternalCost,6600000, +2025-06,Q2-2025,2025,MOTOR,Premium,55000000,52250000 +2025-06,Q2-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-06,Q2-2025,2025,SPECIALTY_AVTN,Claims,15750000,14962500 +2025-06,Q2-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-06,Q2-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2375000 +2025-06,Q2-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-06,Q2-2025,2025,SPECIALTY_AVTN,Premium,25000000,23750000 +2025-06,Q2-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-06,Q2-2025,2025,TECH_RISK,Claims,15273244,14509582 +2025-06,Q2-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-06,Q2-2025,2025,TECH_RISK,ExternalCost,3200000,3040000 +2025-06,Q2-2025,2025,TECH_RISK,InternalCost,3840000, +2025-06,Q2-2025,2025,TECH_RISK,Premium,32000000,30400000 +2025-06,Q2-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-06,Q2-2025,2025,TRANSPORT,Claims,12926222,12279911 +2025-06,Q2-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-06,Q2-2025,2025,TRANSPORT,ExternalCost,2200000,2090000 +2025-06,Q2-2025,2025,TRANSPORT,InternalCost,2640000, +2025-06,Q2-2025,2025,TRANSPORT,Premium,22000000,20900000 +2025-07,Q3-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-07,Q3-2025,2025,COMM_FIRE,Claims,30760000,32605600 +2025-07,Q3-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-07,Q3-2025,2025,COMM_FIRE,ExternalCost,4500000,4770000 +2025-07,Q3-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-07,Q3-2025,2025,COMM_FIRE,Premium,45000000,47700000 +2025-07,Q3-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-07,Q3-2025,2025,HOUSEHOLD,Claims,47458925,50306460 +2025-07,Q3-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-07,Q3-2025,2025,HOUSEHOLD,ExternalCost,7500000,7950000 +2025-07,Q3-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-07,Q3-2025,2025,HOUSEHOLD,Premium,82500000,87450000 +2025-07,Q3-2025,2025,LIABILITY,CapitalCost,2090000, +2025-07,Q3-2025,2025,LIABILITY,Claims,23940000,25376400 +2025-07,Q3-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-07,Q3-2025,2025,LIABILITY,ExternalCost,3800000,4028000 +2025-07,Q3-2025,2025,LIABILITY,InternalCost,4560000, +2025-07,Q3-2025,2025,LIABILITY,Premium,38000000,40280000 +2025-07,Q3-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-07,Q3-2025,2025,LIFE_HEALTH_EU,Claims,27840000,29510400 +2025-07,Q3-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-07,Q3-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,5088000 +2025-07,Q3-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-07,Q3-2025,2025,LIFE_HEALTH_EU,Premium,48000000,50880000 +2025-07,Q3-2025,2025,MOTOR,CapitalCost,3025000, +2025-07,Q3-2025,2025,MOTOR,Claims,43569778,46183965 +2025-07,Q3-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-07,Q3-2025,2025,MOTOR,ExternalCost,5500000,5830000 +2025-07,Q3-2025,2025,MOTOR,InternalCost,6600000, +2025-07,Q3-2025,2025,MOTOR,Premium,55000000,58300000 +2025-07,Q3-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-07,Q3-2025,2025,SPECIALTY_AVTN,Claims,15750000,16695000 +2025-07,Q3-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-07,Q3-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2650000 +2025-07,Q3-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-07,Q3-2025,2025,SPECIALTY_AVTN,Premium,25000000,26500000 +2025-07,Q3-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-07,Q3-2025,2025,TECH_RISK,Claims,16066844,17030855 +2025-07,Q3-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-07,Q3-2025,2025,TECH_RISK,ExternalCost,3200000,3392000 +2025-07,Q3-2025,2025,TECH_RISK,InternalCost,3840000, +2025-07,Q3-2025,2025,TECH_RISK,Premium,32000000,33920000 +2025-07,Q3-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-07,Q3-2025,2025,TRANSPORT,Claims,13542222,14354755 +2025-07,Q3-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-07,Q3-2025,2025,TRANSPORT,ExternalCost,2200000,2332000 +2025-07,Q3-2025,2025,TRANSPORT,InternalCost,2640000, +2025-07,Q3-2025,2025,TRANSPORT,Premium,22000000,23320000 +2025-08,Q3-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-08,Q3-2025,2025,COMM_FIRE,Claims,31930000,31291400 +2025-08,Q3-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-08,Q3-2025,2025,COMM_FIRE,ExternalCost,4500000,4410000 +2025-08,Q3-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-08,Q3-2025,2025,COMM_FIRE,Premium,45000000,44100000 +2025-08,Q3-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-08,Q3-2025,2025,HOUSEHOLD,Claims,52074581,51033089 +2025-08,Q3-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-08,Q3-2025,2025,HOUSEHOLD,ExternalCost,7500000,7350000 +2025-08,Q3-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-08,Q3-2025,2025,HOUSEHOLD,Premium,81000000,79380000 +2025-08,Q3-2025,2025,LIABILITY,CapitalCost,2090000, +2025-08,Q3-2025,2025,LIABILITY,Claims,23940000,23461200 +2025-08,Q3-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-08,Q3-2025,2025,LIABILITY,ExternalCost,3800000,3724000 +2025-08,Q3-2025,2025,LIABILITY,InternalCost,4560000, +2025-08,Q3-2025,2025,LIABILITY,Premium,38000000,37240000 +2025-08,Q3-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-08,Q3-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27283200 +2025-08,Q3-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-08,Q3-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4704000 +2025-08,Q3-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-08,Q3-2025,2025,LIFE_HEALTH_EU,Premium,48000000,47040000 +2025-08,Q3-2025,2025,MOTOR,CapitalCost,3025000, +2025-08,Q3-2025,2025,MOTOR,Claims,42073778,41232302 +2025-08,Q3-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-08,Q3-2025,2025,MOTOR,ExternalCost,5500000,5390000 +2025-08,Q3-2025,2025,MOTOR,InternalCost,6600000, +2025-08,Q3-2025,2025,MOTOR,Premium,55000000,53900000 +2025-08,Q3-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-08,Q3-2025,2025,SPECIALTY_AVTN,Claims,15750000,15435000 +2025-08,Q3-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-08,Q3-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2450000 +2025-08,Q3-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-08,Q3-2025,2025,SPECIALTY_AVTN,Premium,25000000,24500000 +2025-08,Q3-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-08,Q3-2025,2025,TECH_RISK,Claims,14479644,14190051 +2025-08,Q3-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-08,Q3-2025,2025,TECH_RISK,ExternalCost,3200000,3136000 +2025-08,Q3-2025,2025,TECH_RISK,InternalCost,3840000, +2025-08,Q3-2025,2025,TECH_RISK,Premium,32000000,31360000 +2025-08,Q3-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-08,Q3-2025,2025,TRANSPORT,Claims,14158222,13875058 +2025-08,Q3-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-08,Q3-2025,2025,TRANSPORT,ExternalCost,2200000,2156000 +2025-08,Q3-2025,2025,TRANSPORT,InternalCost,2640000, +2025-08,Q3-2025,2025,TRANSPORT,Premium,22000000,21560000 +2025-09,Q3-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-09,Q3-2025,2025,COMM_FIRE,Claims,30760000,31067600 +2025-09,Q3-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-09,Q3-2025,2025,COMM_FIRE,ExternalCost,4500000,4545000 +2025-09,Q3-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-09,Q3-2025,2025,COMM_FIRE,Premium,45000000,45450000 +2025-09,Q3-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-09,Q3-2025,2025,HOUSEHOLD,Claims,56568065,57133746 +2025-09,Q3-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-09,Q3-2025,2025,HOUSEHOLD,ExternalCost,7500000,7575000 +2025-09,Q3-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-09,Q3-2025,2025,HOUSEHOLD,Premium,78750000,79537500 +2025-09,Q3-2025,2025,LIABILITY,CapitalCost,2090000, +2025-09,Q3-2025,2025,LIABILITY,Claims,23940000,24179400 +2025-09,Q3-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-09,Q3-2025,2025,LIABILITY,ExternalCost,3800000,3838000 +2025-09,Q3-2025,2025,LIABILITY,InternalCost,4560000, +2025-09,Q3-2025,2025,LIABILITY,Premium,38000000,38380000 +2025-09,Q3-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-09,Q3-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28118400 +2025-09,Q3-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-09,Q3-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4848000 +2025-09,Q3-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-09,Q3-2025,2025,LIFE_HEALTH_EU,Premium,48000000,48480000 +2025-09,Q3-2025,2025,MOTOR,CapitalCost,3025000, +2025-09,Q3-2025,2025,MOTOR,Claims,40577778,40983556 +2025-09,Q3-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-09,Q3-2025,2025,MOTOR,ExternalCost,5500000,5555000 +2025-09,Q3-2025,2025,MOTOR,InternalCost,6600000, +2025-09,Q3-2025,2025,MOTOR,Premium,55000000,55550000 +2025-09,Q3-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-09,Q3-2025,2025,SPECIALTY_AVTN,Claims,15750000,15907500 +2025-09,Q3-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-09,Q3-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2525000 +2025-09,Q3-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-09,Q3-2025,2025,SPECIALTY_AVTN,Premium,25000000,25250000 +2025-09,Q3-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-09,Q3-2025,2025,TECH_RISK,Claims,15273244,15425976 +2025-09,Q3-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-09,Q3-2025,2025,TECH_RISK,ExternalCost,3200000,3232000 +2025-09,Q3-2025,2025,TECH_RISK,InternalCost,3840000, +2025-09,Q3-2025,2025,TECH_RISK,Premium,32000000,32320000 +2025-09,Q3-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-09,Q3-2025,2025,TRANSPORT,Claims,14774222,14921964 +2025-09,Q3-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-09,Q3-2025,2025,TRANSPORT,ExternalCost,2200000,2222000 +2025-09,Q3-2025,2025,TRANSPORT,InternalCost,2640000, +2025-09,Q3-2025,2025,TRANSPORT,Premium,22000000,22220000 +2025-10,Q4-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-10,Q4-2025,2025,COMM_FIRE,Claims,27250000,26432500 +2025-10,Q4-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-10,Q4-2025,2025,COMM_FIRE,ExternalCost,4500000,4365000 +2025-10,Q4-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-10,Q4-2025,2025,COMM_FIRE,Premium,45000000,43650000 +2025-10,Q4-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-10,Q4-2025,2025,HOUSEHOLD,Claims,52717205,51135689 +2025-10,Q4-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-10,Q4-2025,2025,HOUSEHOLD,ExternalCost,7500000,7275000 +2025-10,Q4-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-10,Q4-2025,2025,HOUSEHOLD,Premium,75000000,72750000 +2025-10,Q4-2025,2025,LIABILITY,CapitalCost,2090000, +2025-10,Q4-2025,2025,LIABILITY,Claims,23940000,23221800 +2025-10,Q4-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-10,Q4-2025,2025,LIABILITY,ExternalCost,3800000,3686000 +2025-10,Q4-2025,2025,LIABILITY,InternalCost,4560000, +2025-10,Q4-2025,2025,LIABILITY,Premium,38000000,36860000 +2025-10,Q4-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-10,Q4-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27004800 +2025-10,Q4-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-10,Q4-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4656000 +2025-10,Q4-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-10,Q4-2025,2025,LIFE_HEALTH_EU,Premium,48000000,46560000 +2025-10,Q4-2025,2025,MOTOR,CapitalCost,3025000, +2025-10,Q4-2025,2025,MOTOR,Claims,39081778,37909325 +2025-10,Q4-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-10,Q4-2025,2025,MOTOR,ExternalCost,5500000,5335000 +2025-10,Q4-2025,2025,MOTOR,InternalCost,6600000, +2025-10,Q4-2025,2025,MOTOR,Premium,55000000,53350000 +2025-10,Q4-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-10,Q4-2025,2025,SPECIALTY_AVTN,Claims,15750000,15277500 +2025-10,Q4-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-10,Q4-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2425000 +2025-10,Q4-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-10,Q4-2025,2025,SPECIALTY_AVTN,Premium,25000000,24250000 +2025-10,Q4-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-10,Q4-2025,2025,TECH_RISK,Claims,16860444,16354631 +2025-10,Q4-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-10,Q4-2025,2025,TECH_RISK,ExternalCost,3200000,3104000 +2025-10,Q4-2025,2025,TECH_RISK,InternalCost,3840000, +2025-10,Q4-2025,2025,TECH_RISK,Premium,32000000,31040000 +2025-10,Q4-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-10,Q4-2025,2025,TRANSPORT,Claims,15390222,14928515 +2025-10,Q4-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-10,Q4-2025,2025,TRANSPORT,ExternalCost,2200000,2134000 +2025-10,Q4-2025,2025,TRANSPORT,InternalCost,2640000, +2025-10,Q4-2025,2025,TRANSPORT,Premium,22000000,21340000 +2025-11,Q4-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-11,Q4-2025,2025,COMM_FIRE,Claims,26080000,26862400 +2025-11,Q4-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-11,Q4-2025,2025,COMM_FIRE,ExternalCost,4500000,4635000 +2025-11,Q4-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-11,Q4-2025,2025,COMM_FIRE,Premium,45000000,46350000 +2025-11,Q4-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-11,Q4-2025,2025,HOUSEHOLD,Claims,47246345,48663735 +2025-11,Q4-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-11,Q4-2025,2025,HOUSEHOLD,ExternalCost,7500000,7725000 +2025-11,Q4-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-11,Q4-2025,2025,HOUSEHOLD,Premium,71250000,73387500 +2025-11,Q4-2025,2025,LIABILITY,CapitalCost,2090000, +2025-11,Q4-2025,2025,LIABILITY,Claims,23940000,24658200 +2025-11,Q4-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-11,Q4-2025,2025,LIABILITY,ExternalCost,3800000,3914000 +2025-11,Q4-2025,2025,LIABILITY,InternalCost,4560000, +2025-11,Q4-2025,2025,LIABILITY,Premium,38000000,39140000 +2025-11,Q4-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-11,Q4-2025,2025,LIFE_HEALTH_EU,Claims,27840000,28675200 +2025-11,Q4-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-11,Q4-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4944000 +2025-11,Q4-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-11,Q4-2025,2025,LIFE_HEALTH_EU,Premium,48000000,49440000 +2025-11,Q4-2025,2025,MOTOR,CapitalCost,3025000, +2025-11,Q4-2025,2025,MOTOR,Claims,37585778,38713351 +2025-11,Q4-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-11,Q4-2025,2025,MOTOR,ExternalCost,5500000,5665000 +2025-11,Q4-2025,2025,MOTOR,InternalCost,6600000, +2025-11,Q4-2025,2025,MOTOR,Premium,55000000,56650000 +2025-11,Q4-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-11,Q4-2025,2025,SPECIALTY_AVTN,Claims,15750000,16222500 +2025-11,Q4-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-11,Q4-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2575000 +2025-11,Q4-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-11,Q4-2025,2025,SPECIALTY_AVTN,Premium,25000000,25750000 +2025-11,Q4-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-11,Q4-2025,2025,TECH_RISK,Claims,17654044,18183665 +2025-11,Q4-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-11,Q4-2025,2025,TECH_RISK,ExternalCost,3200000,3296000 +2025-11,Q4-2025,2025,TECH_RISK,InternalCost,3840000, +2025-11,Q4-2025,2025,TECH_RISK,Premium,32000000,32960000 +2025-11,Q4-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-11,Q4-2025,2025,TRANSPORT,Claims,16006222,16486409 +2025-11,Q4-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-11,Q4-2025,2025,TRANSPORT,ExternalCost,2200000,2266000 +2025-11,Q4-2025,2025,TRANSPORT,InternalCost,2640000, +2025-11,Q4-2025,2025,TRANSPORT,Premium,22000000,22660000 +2025-12,Q4-2025,2025,COMM_FIRE,CapitalCost,2475000, +2025-12,Q4-2025,2025,COMM_FIRE,Claims,28420000,28420000 +2025-12,Q4-2025,2025,COMM_FIRE,ExpectedProfit,2250000, +2025-12,Q4-2025,2025,COMM_FIRE,ExternalCost,4500000,4500000 +2025-12,Q4-2025,2025,COMM_FIRE,InternalCost,5400000, +2025-12,Q4-2025,2025,COMM_FIRE,Premium,45000000,45000000 +2025-12,Q4-2025,2025,HOUSEHOLD,CapitalCost,4125000, +2025-12,Q4-2025,2025,HOUSEHOLD,Claims,48255484,48255484 +2025-12,Q4-2025,2025,HOUSEHOLD,ExpectedProfit,3750000, +2025-12,Q4-2025,2025,HOUSEHOLD,ExternalCost,7500000,7500000 +2025-12,Q4-2025,2025,HOUSEHOLD,InternalCost,9000000, +2025-12,Q4-2025,2025,HOUSEHOLD,Premium,67500000,67500000 +2025-12,Q4-2025,2025,LIABILITY,CapitalCost,2090000, +2025-12,Q4-2025,2025,LIABILITY,Claims,23940000,23940000 +2025-12,Q4-2025,2025,LIABILITY,ExpectedProfit,1900000, +2025-12,Q4-2025,2025,LIABILITY,ExternalCost,3800000,3800000 +2025-12,Q4-2025,2025,LIABILITY,InternalCost,4560000, +2025-12,Q4-2025,2025,LIABILITY,Premium,38000000,38000000 +2025-12,Q4-2025,2025,LIFE_HEALTH_EU,CapitalCost,2640000, +2025-12,Q4-2025,2025,LIFE_HEALTH_EU,Claims,27840000,27840000 +2025-12,Q4-2025,2025,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2025-12,Q4-2025,2025,LIFE_HEALTH_EU,ExternalCost,4800000,4800000 +2025-12,Q4-2025,2025,LIFE_HEALTH_EU,InternalCost,5760000, +2025-12,Q4-2025,2025,LIFE_HEALTH_EU,Premium,48000000,48000000 +2025-12,Q4-2025,2025,MOTOR,CapitalCost,3025000, +2025-12,Q4-2025,2025,MOTOR,Claims,36089778,36089778 +2025-12,Q4-2025,2025,MOTOR,ExpectedProfit,2750000, +2025-12,Q4-2025,2025,MOTOR,ExternalCost,5500000,5500000 +2025-12,Q4-2025,2025,MOTOR,InternalCost,6600000, +2025-12,Q4-2025,2025,MOTOR,Premium,55000000,55000000 +2025-12,Q4-2025,2025,SPECIALTY_AVTN,CapitalCost,1375000, +2025-12,Q4-2025,2025,SPECIALTY_AVTN,Claims,15750000,15750000 +2025-12,Q4-2025,2025,SPECIALTY_AVTN,ExpectedProfit,1250000, +2025-12,Q4-2025,2025,SPECIALTY_AVTN,ExternalCost,2500000,2500000 +2025-12,Q4-2025,2025,SPECIALTY_AVTN,InternalCost,3000000, +2025-12,Q4-2025,2025,SPECIALTY_AVTN,Premium,25000000,25000000 +2025-12,Q4-2025,2025,TECH_RISK,CapitalCost,1760000, +2025-12,Q4-2025,2025,TECH_RISK,Claims,20034844,20034844 +2025-12,Q4-2025,2025,TECH_RISK,ExpectedProfit,1600000, +2025-12,Q4-2025,2025,TECH_RISK,ExternalCost,3200000,3200000 +2025-12,Q4-2025,2025,TECH_RISK,InternalCost,3840000, +2025-12,Q4-2025,2025,TECH_RISK,Premium,32000000,32000000 +2025-12,Q4-2025,2025,TRANSPORT,CapitalCost,1210000, +2025-12,Q4-2025,2025,TRANSPORT,Claims,16622222,16622222 +2025-12,Q4-2025,2025,TRANSPORT,ExpectedProfit,1100000, +2025-12,Q4-2025,2025,TRANSPORT,ExternalCost,2200000,2200000 +2025-12,Q4-2025,2025,TRANSPORT,InternalCost,2640000, +2025-12,Q4-2025,2025,TRANSPORT,Premium,22000000,22000000 +2026-01,Q1-2026,2026,COMM_FIRE,CapitalCost,2475000, +2026-01,Q1-2026,2026,COMM_FIRE,Claims,28420000,27283200 +2026-01,Q1-2026,2026,COMM_FIRE,ExpectedProfit,2250000, +2026-01,Q1-2026,2026,COMM_FIRE,ExternalCost,4500000,4320000 +2026-01,Q1-2026,2026,COMM_FIRE,InternalCost,5400000, +2026-01,Q1-2026,2026,COMM_FIRE,Premium,45000000,43200000 +2026-01,Q1-2026,2026,HOUSEHOLD,CapitalCost,4125000, +2026-01,Q1-2026,2026,HOUSEHOLD,Claims,48866345,46911691 +2026-01,Q1-2026,2026,HOUSEHOLD,ExpectedProfit,3750000, +2026-01,Q1-2026,2026,HOUSEHOLD,ExternalCost,7500000,7200000 +2026-01,Q1-2026,2026,HOUSEHOLD,InternalCost,9000000, +2026-01,Q1-2026,2026,HOUSEHOLD,Premium,71250000,68400000 +2026-01,Q1-2026,2026,LIABILITY,CapitalCost,2090000, +2026-01,Q1-2026,2026,LIABILITY,Claims,23940000,22982400 +2026-01,Q1-2026,2026,LIABILITY,ExpectedProfit,1900000, +2026-01,Q1-2026,2026,LIABILITY,ExternalCost,3800000,3648000 +2026-01,Q1-2026,2026,LIABILITY,InternalCost,4560000, +2026-01,Q1-2026,2026,LIABILITY,Premium,38000000,36480000 +2026-01,Q1-2026,2026,LIFE_HEALTH_EU,CapitalCost,2640000, +2026-01,Q1-2026,2026,LIFE_HEALTH_EU,Claims,27840000,26726400 +2026-01,Q1-2026,2026,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2026-01,Q1-2026,2026,LIFE_HEALTH_EU,ExternalCost,4800000,4608000 +2026-01,Q1-2026,2026,LIFE_HEALTH_EU,InternalCost,5760000, +2026-01,Q1-2026,2026,LIFE_HEALTH_EU,Premium,48000000,46080000 +2026-01,Q1-2026,2026,MOTOR,CapitalCost,3025000, +2026-01,Q1-2026,2026,MOTOR,Claims,36089778,34646187 +2026-01,Q1-2026,2026,MOTOR,ExpectedProfit,2750000, +2026-01,Q1-2026,2026,MOTOR,ExternalCost,5500000,5280000 +2026-01,Q1-2026,2026,MOTOR,InternalCost,6600000, +2026-01,Q1-2026,2026,MOTOR,Premium,55000000,52800000 +2026-01,Q1-2026,2026,SPECIALTY_AVTN,CapitalCost,1375000, +2026-01,Q1-2026,2026,SPECIALTY_AVTN,Claims,15750000,15120000 +2026-01,Q1-2026,2026,SPECIALTY_AVTN,ExpectedProfit,1250000, +2026-01,Q1-2026,2026,SPECIALTY_AVTN,ExternalCost,2500000,2400000 +2026-01,Q1-2026,2026,SPECIALTY_AVTN,InternalCost,3000000, +2026-01,Q1-2026,2026,SPECIALTY_AVTN,Premium,25000000,24000000 +2026-01,Q1-2026,2026,TECH_RISK,CapitalCost,1760000, +2026-01,Q1-2026,2026,TECH_RISK,Claims,18447644,17709738 +2026-01,Q1-2026,2026,TECH_RISK,ExpectedProfit,1600000, +2026-01,Q1-2026,2026,TECH_RISK,ExternalCost,3200000,3072000 +2026-01,Q1-2026,2026,TECH_RISK,InternalCost,3840000, +2026-01,Q1-2026,2026,TECH_RISK,Premium,32000000,30720000 +2026-01,Q1-2026,2026,TRANSPORT,CapitalCost,1210000, +2026-01,Q1-2026,2026,TRANSPORT,Claims,15390222,14774613 +2026-01,Q1-2026,2026,TRANSPORT,ExpectedProfit,1100000, +2026-01,Q1-2026,2026,TRANSPORT,ExternalCost,2200000,2112000 +2026-01,Q1-2026,2026,TRANSPORT,InternalCost,2640000, +2026-01,Q1-2026,2026,TRANSPORT,Premium,22000000,21120000 +2026-02,Q1-2026,2026,COMM_FIRE,CapitalCost,2475000, +2026-02,Q1-2026,2026,COMM_FIRE,Claims,27250000,27795000 +2026-02,Q1-2026,2026,COMM_FIRE,ExpectedProfit,2250000, +2026-02,Q1-2026,2026,COMM_FIRE,ExternalCost,4500000,4590000 +2026-02,Q1-2026,2026,COMM_FIRE,InternalCost,5400000, +2026-02,Q1-2026,2026,COMM_FIRE,Premium,45000000,45900000 +2026-02,Q1-2026,2026,HOUSEHOLD,CapitalCost,4125000, +2026-02,Q1-2026,2026,HOUSEHOLD,Claims,46879829,47817426 +2026-02,Q1-2026,2026,HOUSEHOLD,ExpectedProfit,3750000, +2026-02,Q1-2026,2026,HOUSEHOLD,ExternalCost,7500000,7650000 +2026-02,Q1-2026,2026,HOUSEHOLD,InternalCost,9000000, +2026-02,Q1-2026,2026,HOUSEHOLD,Premium,69000000,70380000 +2026-02,Q1-2026,2026,LIABILITY,CapitalCost,2090000, +2026-02,Q1-2026,2026,LIABILITY,Claims,23940000,24418800 +2026-02,Q1-2026,2026,LIABILITY,ExpectedProfit,1900000, +2026-02,Q1-2026,2026,LIABILITY,ExternalCost,3800000,3876000 +2026-02,Q1-2026,2026,LIABILITY,InternalCost,4560000, +2026-02,Q1-2026,2026,LIABILITY,Premium,38000000,38760000 +2026-02,Q1-2026,2026,LIFE_HEALTH_EU,CapitalCost,2640000, +2026-02,Q1-2026,2026,LIFE_HEALTH_EU,Claims,27840000,28396800 +2026-02,Q1-2026,2026,LIFE_HEALTH_EU,ExpectedProfit,2400000, +2026-02,Q1-2026,2026,LIFE_HEALTH_EU,ExternalCost,4800000,4896000 +2026-02,Q1-2026,2026,LIFE_HEALTH_EU,InternalCost,5760000, +2026-02,Q1-2026,2026,LIFE_HEALTH_EU,Premium,48000000,48960000 +2026-02,Q1-2026,2026,MOTOR,CapitalCost,3025000, +2026-02,Q1-2026,2026,MOTOR,Claims,34593778,35285654 +2026-02,Q1-2026,2026,MOTOR,ExpectedProfit,2750000, +2026-02,Q1-2026,2026,MOTOR,ExternalCost,5500000,5610000 +2026-02,Q1-2026,2026,MOTOR,InternalCost,6600000, +2026-02,Q1-2026,2026,MOTOR,Premium,55000000,56100000 +2026-02,Q1-2026,2026,SPECIALTY_AVTN,CapitalCost,1375000, +2026-02,Q1-2026,2026,SPECIALTY_AVTN,Claims,15750000,16065000 +2026-02,Q1-2026,2026,SPECIALTY_AVTN,ExpectedProfit,1250000, +2026-02,Q1-2026,2026,SPECIALTY_AVTN,ExternalCost,2500000,2550000 +2026-02,Q1-2026,2026,SPECIALTY_AVTN,InternalCost,3000000, +2026-02,Q1-2026,2026,SPECIALTY_AVTN,Premium,25000000,25500000 +2026-02,Q1-2026,2026,TECH_RISK,CapitalCost,1760000, +2026-02,Q1-2026,2026,TECH_RISK,Claims,16860444,17197653 +2026-02,Q1-2026,2026,TECH_RISK,ExpectedProfit,1600000, +2026-02,Q1-2026,2026,TECH_RISK,ExternalCost,3200000,3264000 +2026-02,Q1-2026,2026,TECH_RISK,InternalCost,3840000, +2026-02,Q1-2026,2026,TECH_RISK,Premium,32000000,32640000 +2026-02,Q1-2026,2026,TRANSPORT,CapitalCost,1210000, +2026-02,Q1-2026,2026,TRANSPORT,Claims,14774222,15069706 +2026-02,Q1-2026,2026,TRANSPORT,ExpectedProfit,1100000, +2026-02,Q1-2026,2026,TRANSPORT,ExternalCost,2200000,2244000 +2026-02,Q1-2026,2026,TRANSPORT,InternalCost,2640000, +2026-02,Q1-2026,2026,TRANSPORT,Premium,22000000,22440000 diff --git a/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg index 021b97c12..ef82d4a2f 100644 --- a/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/AmericasIns/LineOfBusiness/icon.svg @@ -3,6 +3,11 @@ - - US + + + + US + + + diff --git a/samples/Graph/content/FutuRe/AmericasIns/icon.svg b/samples/Graph/content/FutuRe/AmericasIns/icon.svg index 332f22efd..4f4b6e58e 100644 --- a/samples/Graph/content/FutuRe/AmericasIns/icon.svg +++ b/samples/Graph/content/FutuRe/AmericasIns/icon.svg @@ -10,6 +10,11 @@ - - US + + + + US + + + diff --git a/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg index 59d73f483..0c01f1c82 100644 --- a/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/AsiaRe/LineOfBusiness/icon.svg @@ -3,6 +3,11 @@ - - ASIA + + + + ASIA + + + diff --git a/samples/Graph/content/FutuRe/AsiaRe/icon.svg b/samples/Graph/content/FutuRe/AsiaRe/icon.svg index 2889851db..7dcef9e79 100644 --- a/samples/Graph/content/FutuRe/AsiaRe/icon.svg +++ b/samples/Graph/content/FutuRe/AsiaRe/icon.svg @@ -10,6 +10,11 @@ - - ASIA + + + + ASIA + + + diff --git a/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg index d1b247d33..14c3070d7 100644 --- a/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/EuropeRe/LineOfBusiness/icon.svg @@ -3,6 +3,11 @@ - - EU + + + + EU + + + diff --git a/samples/Graph/content/FutuRe/EuropeRe/icon.svg b/samples/Graph/content/FutuRe/EuropeRe/icon.svg index 9059640e6..fda570353 100644 --- a/samples/Graph/content/FutuRe/EuropeRe/icon.svg +++ b/samples/Graph/content/FutuRe/EuropeRe/icon.svg @@ -10,6 +10,11 @@ - - EU + + + + EU + + + diff --git a/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg b/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg index 0adbc29f9..909ff7ae8 100644 --- a/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg +++ b/samples/Graph/content/FutuRe/LineOfBusiness/icon.svg @@ -3,6 +3,11 @@ - - GROUP + + + + GROUP + + + diff --git a/src/MeshWeaver.AI.AzureFoundry/AzureClaudeChatClient.cs b/src/MeshWeaver.AI.AzureFoundry/AzureClaudeChatClient.cs index bf64287aa..b43300f13 100644 --- a/src/MeshWeaver.AI.AzureFoundry/AzureClaudeChatClient.cs +++ b/src/MeshWeaver.AI.AzureFoundry/AzureClaudeChatClient.cs @@ -15,7 +15,7 @@ namespace MeshWeaver.AI.AzureFoundry; public class AzureClaudeChatClient : IChatClient { private const string AnthropicVersion = "2023-06-01"; - private const int DefaultMaxTokens = 4096; + private const int DefaultMaxTokens = 16384; private readonly HttpClient httpClient; private readonly string endpoint; @@ -91,14 +91,36 @@ public async IAsyncEnumerable GetStreamingResponseAsync( [EnumeratorCancellation] CancellationToken cancellationToken = default) { var request = BuildRequest(messages, options, stream: true); - var httpRequest = CreateHttpRequest(request); - using var response = await httpClient.SendAsync( - httpRequest, - HttpCompletionOption.ResponseHeadersRead, - cancellationToken); + // Retry on transient failures (500, 502, 503, 429) + HttpResponseMessage? response = null; + for (var attempt = 0; attempt < 3; attempt++) + { + var httpRequest = CreateHttpRequest(request); + response = await httpClient.SendAsync( + httpRequest, + HttpCompletionOption.ResponseHeadersRead, + cancellationToken); + + if (response.IsSuccessStatusCode) + break; + + var status = (int)response.StatusCode; + var errorBody = await response.Content.ReadAsStringAsync(cancellationToken); + logger?.LogWarning("Azure AI API {Status} on attempt {Attempt}: {Body}", + status, attempt + 1, errorBody?.Length > 500 ? errorBody[..500] : errorBody); + + if (status is 500 or 502 or 503 or 429 && attempt < 2) + { + var delay = status == 429 ? 5000 : 1000 * (attempt + 1); + response.Dispose(); + await Task.Delay(delay, cancellationToken); + continue; + } + response.EnsureSuccessStatusCode(); // throws + } - response.EnsureSuccessStatusCode(); + response!.EnsureSuccessStatusCode(); using var stream = await response.Content.ReadAsStreamAsync(cancellationToken); using var reader = new StreamReader(stream); @@ -277,6 +299,21 @@ private ClaudeRequest BuildRequest(IEnumerable messages, ChatOption ResultContent = functionResult.Result?.ToString() ?? string.Empty }); break; + + case DataContent dataContent when dataContent.Data.Length > 0: + // Binary content (PDF, images) — sent as base64 + var mediaType = dataContent.MediaType ?? "application/octet-stream"; + contentBlocks.Add(new ClaudeContentBlock + { + Type = mediaType.StartsWith("image/") ? "image" : "document", + Source = new + { + type = "base64", + media_type = mediaType, + data = Convert.ToBase64String(dataContent.Data.ToArray()) + } + }); + break; } } @@ -498,6 +535,7 @@ private class ClaudeContentBlock public string? ToolUseId { get; set; } [JsonPropertyName("content")] public string? ResultContent { get; set; } + public object? Source { get; set; } } private class ClaudeTool diff --git a/src/MeshWeaver.AI/AIExtensions.cs b/src/MeshWeaver.AI/AIExtensions.cs index e2ad3dd1a..8c021acc7 100644 --- a/src/MeshWeaver.AI/AIExtensions.cs +++ b/src/MeshWeaver.AI/AIExtensions.cs @@ -23,6 +23,12 @@ public TBuilder AddAI() .AddThreadType() .AddAgentType() .ConfigureServices(services => services.AddAgentChatServices()) + // Register AI types on the MESH hub (for MeshQuery deserialization of Thread content) + .ConfigureHub(config => + { + config.TypeRegistry.AddAITypes(); + return config; + }) .ConfigureDefaultNodeHub(config => { config.TypeRegistry.AddAITypes(); @@ -74,12 +80,12 @@ public static ITypeRegistry AddAITypes(this ITypeRegistry typeRegistry) .WithType(typeof(CancelThreadStreamRequest), nameof(CancelThreadStreamRequest)) .WithType(typeof(ResubmitMessageRequest), nameof(ResubmitMessageRequest)) .WithType(typeof(DeleteFromMessageRequest), nameof(DeleteFromMessageRequest)) - .WithType(typeof(EditMessageRequest), nameof(EditMessageRequest)) .WithType(typeof(ToolCallEntry), nameof(ToolCallEntry)) .WithType(typeof(UpdateThreadMessageContent), nameof(UpdateThreadMessageContent)) .WithType(typeof(DelegationCompletedEvent), nameof(DelegationCompletedEvent)) .WithType(typeof(NodeChangeEntry), nameof(NodeChangeEntry)) .WithType(typeof(ThreadExecutionContext), nameof(ThreadExecutionContext)) + // ChatHistoryEntry removed — ChatHistory uses string[] to avoid $type issues .WithType(typeof(SaveContentRequest), nameof(SaveContentRequest)) .WithType(typeof(SaveContentResponse), nameof(SaveContentResponse)); diff --git a/src/MeshWeaver.AI/AgentChatClient.cs b/src/MeshWeaver.AI/AgentChatClient.cs index b44d19e2d..7fd7753c3 100644 --- a/src/MeshWeaver.AI/AgentChatClient.cs +++ b/src/MeshWeaver.AI/AgentChatClient.cs @@ -1,4 +1,5 @@ -using System.Collections.Immutable; +using System.Collections.Concurrent; +using System.Collections.Immutable; using System.Reactive.Linq; using System.Runtime.CompilerServices; using System.Text; @@ -6,6 +7,7 @@ using System.Text.RegularExpressions; using MeshWeaver.AI.Persistence; using MeshWeaver.Data; +using MeshWeaver.Graph; using MeshWeaver.Layout; using MeshWeaver.Mesh.Services; using MeshWeaver.Messaging; @@ -65,12 +67,17 @@ public AgentChatClient(IServiceProvider serviceProvider) /// public string? LastDelegationPath { get; set; } + /// + public ConcurrentDictionary DelegationPaths { get; } = new(); + /// public Action? UpdateDelegationStatus { get; set; } /// public Action? ForwardToolCall { get; set; } + /// + public Action? ForwardNodeChange { get; set; } /// Sets the execution context for delegation sub-thread creation. public void SetExecutionContext(ThreadExecutionContext? ctx) => ExecutionContext = ctx; @@ -98,6 +105,18 @@ public void SetPersistentThreadId(string? persistentId) } } + /// + /// Returns the ChatClientAgent for the given name (or default). + /// Used by ThreadExecution to call agent.ChatClient.GetStreamingResponseAsync directly. + /// + public ChatClientAgent? GetAgent(string? agentName = null) + { + if (!string.IsNullOrEmpty(agentName) && agents.TryGetValue(agentName, out var named)) + return named; + // Default agent (first in order) + return agents.Values.FirstOrDefault(); + } + /// /// Sets attachment paths whose content will be loaded and included in the next message. /// @@ -158,25 +177,23 @@ private async Task UpdateThreadPersistentIdAsync(string threadNodePath) { try { - var meshQuery = hub.ServiceProvider.GetRequiredService(); - var node = await meshQuery.QueryAsync($"path:{threadNodePath}") - .FirstOrDefaultAsync(); - if (node?.Content is not Thread threadContent) - return; - - // Only update if not already set - if (!string.IsNullOrEmpty(threadContent.PersistentThreadId)) - return; - var factory = GetFactoryForModel(currentModelName); - var updatedContent = threadContent with + var workspace = hub.ServiceProvider.GetRequiredService(); + workspace.UpdateMeshNode(node => { - PersistentThreadId = persistentThreadId, - ProviderType = factory?.Name - }; - - var updatedNode = node with { Content = updatedContent }; - hub.Post(new Data.DataChangeRequest { Updates = [updatedNode] }, o => o.WithTarget(new Messaging.Address(threadNodePath))); + if (node.Content is not Thread threadContent) + return node; + if (!string.IsNullOrEmpty(threadContent.PersistentThreadId)) + return node; // Already set + return node with + { + Content = threadContent with + { + PersistentThreadId = persistentThreadId, + ProviderType = factory?.Name + } + }; + }, address: new Messaging.Address(threadNodePath)); logger.LogInformation("Updated thread {Path} with PersistentThreadId={PersistentThreadId}", threadNodePath, persistentThreadId); @@ -191,7 +208,24 @@ private async Task UpdateThreadPersistentIdAsync(string threadNodePath) /// Builds the static system prompt (agent instructions + tool docs) once, /// then appends dynamic parts (context, attachments, history) on each call. ///
- private async Task BuildMessageWithContextAsync(IReadOnlyCollection messages, string? agentName = null) + private static readonly HashSet BinaryExtensions = new(StringComparer.OrdinalIgnoreCase) + { + ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".tiff" + }; + + private static readonly Dictionary ExtensionToMediaType = new(StringComparer.OrdinalIgnoreCase) + { + [".pdf"] = "application/pdf", + [".png"] = "image/png", + [".jpg"] = "image/jpeg", + [".jpeg"] = "image/jpeg", + [".gif"] = "image/gif", + [".webp"] = "image/webp", + [".bmp"] = "image/bmp", + [".tiff"] = "image/tiff" + }; + + private async Task<(string Text, ImmutableList BinaryAttachments)> BuildMessageWithContextAsync(IReadOnlyCollection messages, string? agentName = null) { var messageText = new StringBuilder(); @@ -293,50 +327,76 @@ private async Task BuildMessageWithContextAsync(IReadOnlyCollection.Empty; + var attachmentHeaderWritten = false; if (attachmentPaths is { Count: > 0 }) { var meshPlugin = new MeshPlugin(hub, this); - var loadTasks = attachmentPaths.Select(async path => + var contentService = hub.ServiceProvider.GetService(); + + foreach (var path in attachmentPaths) { try { - // Skip agent attachments — they override agent selection, not context content var cleanPath = path.TrimStart('@'); if (agentAttachmentPaths?.Contains(cleanPath) == true) - return (Path: path, Content: (string?)null); + continue; + + // Check for content: prefix — binary file from content collection + var contentIdx = cleanPath.IndexOf("content:", StringComparison.OrdinalIgnoreCase); + if (contentIdx >= 0 && contentService != null) + { + var nodePath = contentIdx > 0 ? cleanPath[..(contentIdx - 1)] + : (Context?.Path ?? Context?.Address?.ToString()); + var fileName = cleanPath[(contentIdx + "content:".Length)..]; + var ext = System.IO.Path.GetExtension(fileName); + if (BinaryExtensions.Contains(ext)) + { + // Load binary from content collection on the node's hub + var effectivePath = nodePath ?? Context?.Path; + var stream = await contentService.GetContentAsync("content", fileName); + if (stream != null) + { + using (stream) + { + using var ms = new MemoryStream(); + await stream.CopyToAsync(ms); + var mediaType = ExtensionToMediaType.GetValueOrDefault(ext, "application/octet-stream"); + binaryAttachments = binaryAttachments.Add( + new DataContent(ms.ToArray(), mediaType) { Name = fileName }); + logger.LogInformation("Loaded binary attachment: {FileName} ({MediaType}, {Size} bytes)", + fileName, mediaType, ms.Length); + } + } + continue; + } + } + + // Text attachment — load via MeshPlugin.Get var content = await meshPlugin.Get($"@{cleanPath}"); if (!string.IsNullOrEmpty(content) && !content.StartsWith("Not found") && !content.StartsWith("Error")) { - // Truncate individual attachments to prevent prompt overflow if (content.Length > 8000) content = content[..8000] + "\n... (truncated)"; - return (Path: path, Content: content); + if (!attachmentHeaderWritten) + { + messageText.AppendLine("# Attached Content"); + messageText.AppendLine(); + attachmentHeaderWritten = true; + } + messageText.AppendLine($"## Attachment: {path}"); + messageText.AppendLine(); + messageText.AppendLine(content); + messageText.AppendLine(); } } catch (Exception ex) { logger.LogDebug(ex, "Error loading attachment content for: {Path}", path); } - return (Path: path, Content: (string?)null); - }); - - var results = await Task.WhenAll(loadTasks); - var loadedAttachments = results.Where(r => r.Content != null).ToList(); - - if (loadedAttachments.Count > 0) - { - messageText.AppendLine("# Attached Content"); - messageText.AppendLine(); - foreach (var (path, content) in loadedAttachments) - { - messageText.AppendLine($"## Attachment: {path}"); - messageText.AppendLine(); - messageText.AppendLine(content); - messageText.AppendLine(); - } } } @@ -364,7 +424,7 @@ private async Task BuildMessageWithContextAsync(IReadOnlyCollection @@ -425,11 +485,14 @@ public async IAsyncEnumerable GetResponseAsync( var thread = await GetOrCreateThreadAsync(agent); // Build the user message with context and agent instructions - var userMessage = await BuildMessageWithContextAsync(messages, currentAgentName); + var (userText, binaryParts) = await BuildMessageWithContextAsync(messages, currentAgentName); currentAttachments = null; // Clear after use + // Build ChatMessage with mixed content (text + binary attachments) + var chatMessage = BuildChatMessage(userText, binaryParts); + // Get response from the agent with thread - var response = await agent.RunAsync(userMessage, thread, cancellationToken: cancellationToken); + var response = await agent.RunAsync(chatMessage, thread, cancellationToken: cancellationToken); // Save the updated thread await SaveThreadAsync(agent, thread); @@ -541,12 +604,26 @@ public async IAsyncEnumerable GetStreamingResponseAsync( // Get or create thread for this agent var thread = await GetOrCreateThreadAsync(agent); - // Build the user message with context and agent instructions - var userMessage = await BuildMessageWithContextAsync(messages, currentAgentName); - currentAttachments = null; // Clear after use - - // Get streaming response from the agent with thread - await foreach (var update in agent.RunStreamingAsync(userMessage, thread, cancellationToken: cancellationToken)) + // Pass all messages as separate turns with system prompt prepended. + // The agent's ChatClient includes FunctionInvokingChatClient for tool calls. + var turnMessages = new List(); + if (!string.IsNullOrEmpty(agent.Instructions)) + turnMessages.Add(new ChatMessage(ChatRole.System, agent.Instructions)); + turnMessages.AddRange(messages); + logger.LogInformation("[AgentChat] Sending {Count} messages (+ system) to {Agent}", + messages.Count, agent.Name); + currentAttachments = null; + + // ChatOptions MUST include the agent's tools. Without them, the inner + // client (AzureClaudeChatClient) never sends tool definitions to Claude, + // and FunctionInvokingChatClient has nothing to match against. + // Get tools from FunctionInvokingChatClient.AdditionalTools (where the + // ChatClientAgent constructor places them). + var functionInvoker = agent.ChatClient.GetService(); + var chatOptions = new ChatOptions(); + if (functionInvoker?.AdditionalTools is { Count: > 0 } additionalTools) + chatOptions.Tools = additionalTools.ToList(); + await foreach (var update in agent.ChatClient.GetStreamingResponseAsync(turnMessages, chatOptions, cancellationToken)) { // Forward the complete update with all contents (including FunctionCallContent) if (update.Contents.Count > 0) @@ -1254,6 +1331,20 @@ private bool IsAgentPath(string path) a.Name.Equals(path.Split('/').Last(), StringComparison.OrdinalIgnoreCase)); } + /// + /// Builds a ChatMessage with mixed content: text + binary attachments (PDFs, images). + /// If no binary attachments, returns a simple text-only message. + /// + private static ChatMessage BuildChatMessage(string text, ImmutableList binaryAttachments) + { + if (binaryAttachments.Count == 0) + return new ChatMessage(ChatRole.User, text); + + var contents = new List { new TextContent(text) }; + contents.AddRange(binaryAttachments); + return new ChatMessage(ChatRole.User, contents); + } + private void DetectAgentAttachments() { var builder = ImmutableHashSet.CreateBuilder(StringComparer.OrdinalIgnoreCase); diff --git a/src/MeshWeaver.AI/ChatClientAgentFactory.cs b/src/MeshWeaver.AI/ChatClientAgentFactory.cs index ffb7e1b07..5a92a08dc 100644 --- a/src/MeshWeaver.AI/ChatClientAgentFactory.cs +++ b/src/MeshWeaver.AI/ChatClientAgentFactory.cs @@ -1,8 +1,11 @@ using System.Collections.Immutable; +using System.Runtime.CompilerServices; using System.Text; using MeshWeaver.AI.Plugins; using MeshWeaver.Data; +using MeshWeaver.Layout; using MeshWeaver.Graph; +using MeshWeaver.Mesh; using MeshWeaver.Mesh.Services; using MeshWeaver.Messaging; using Microsoft.Agents.AI; @@ -137,16 +140,62 @@ private ChatClientAgent CreateAgentCore( tools = tools.Append(PlanStorageTool.Create(Hub, chat)); + // Wrap all tools to restore user access context before invocation. + // AsyncLocal doesn't flow through the AI framework's streaming + tool invocation, + // so each tool call must explicitly restore the user identity from the + // thread's execution context. This is the single injection point for ALL tools. + var accessService = Hub.ServiceProvider.GetService(); + var wrappedTools = tools.Select(tool => WrapToolWithAccessContext(tool, chat, accessService)).ToList(); + var agent = new ChatClientAgent( chatClient: chatClient, instructions: instructions, name: name, description: description, - tools: tools.ToList(), loggerFactory: null, services: null); + tools: wrappedTools, loggerFactory: null, services: null); var functionInvoker = agent.ChatClient.GetService(); if (functionInvoker != null) + { functionInvoker.AllowConcurrentInvocation = true; + // Log the maximum iterations — if the model tries more tool calls than this, it stops + Logger.LogInformation("[AgentFactory] FunctionInvoker for {Agent}: MaximumIterationsPerRequest={Max}", + name, functionInvoker.MaximumIterationsPerRequest); + } - return agent; + // Wrap with function calling middleware — gives the streaming loop + // real-time visibility into tool calls. FunctionInvokingChatClient + // consumes FunctionCallContent internally; without this middleware, + // the outer stream never sees tool invocations. + return agent.AsBuilder() + .Use((AIAgent _, FunctionInvocationContext ctx, Func> next, CancellationToken ct) => + { + Logger.LogInformation("[Middleware] Tool call: {Name}, ForwardToolCall={HasCallback}", + ctx.Function.Name, chat.ForwardToolCall != null); + var toolEntry = new ToolCallEntry + { + Name = ctx.Function.Name, + DisplayName = ctx.Function.Name, + Arguments = ctx.Arguments?.Count > 0 + ? string.Join(", ", ctx.Arguments.Select(kv => $"{kv.Key}={kv.Value}")) + : null, + Timestamp = DateTime.UtcNow + }; + chat.ForwardToolCall?.Invoke(toolEntry); + return next(ctx, ct); + }) + .Build() as ChatClientAgent ?? agent; + } + + /// + /// Wraps an AITool so that the user's access context is restored before each invocation. + /// This is the single injection point for ALL tool calls — delegation, MeshPlugin, etc. + /// + private static AITool WrapToolWithAccessContext(AITool tool, IAgentChat chat, AccessService? accessService) + { + if (accessService == null || tool is not AIFunction aiFunction) + return tool; + + // Create a wrapper AIFunction that restores access context before delegating + return new AccessContextAIFunction(aiFunction, chat, accessService); } /// @@ -224,9 +273,36 @@ protected virtual IEnumerable GetAgentTools( var execCtx = chat.ExecutionContext; var userIdentity = execCtx?.UserAccessContext?.ObjectId ?? "(no-user)"; + + // Guard: limit delegation depth to prevent recursive delegation. + // Count segments after _Thread/ — each delegation adds msgId/subThreadId (2 segments per level). + // Root thread: Org/_Thread/threadId → 0 extra segments → depth 0 + // 1st delegation: Org/_Thread/threadId/msgId/subId → 2 extra → depth 1 + // 2nd delegation: Org/_Thread/threadId/msgId/subId/msgId2/subId2 → 4 extra → depth 2 + var threadPath = execCtx?.ThreadPath ?? ""; + var threadIdx = threadPath.IndexOf("/_Thread/"); + var depth = 0; + if (threadIdx >= 0) + { + var afterThread = threadPath[(threadIdx + "/_Thread/".Length)..]; + var segments = afterThread.Split('/').Length; + depth = (segments - 1) / 2; // subtract the thread id, each delegation = 2 segments + } + if (depth >= 2) + { + Logger.LogWarning("[Delegation] Max delegation depth ({Depth}) reached at {ThreadPath} for {Source} → {Target}", + depth, threadPath, agentConfig.Id, targetId); + return Task.FromResult(new DelegationResult + { + AgentName = targetId, Task = task, + Result = $"Maximum delegation depth reached ({depth}). You must handle this task directly without further delegation.", + Success = false + }); + } + Logger.LogInformation( - "[Delegation] {Source} → {Target}, user={User}, task={Task}", - agentConfig.Id, targetId, userIdentity, task.Length > 100 ? task[..97] + "..." : task); + "[Delegation] {Source} → {Target}, user={User}, depth={Depth}, task={Task}", + agentConfig.Id, targetId, userIdentity, depth, task.Length > 100 ? task[..97] + "..." : task); if (execCtx == null) { @@ -243,90 +319,102 @@ protected virtual IEnumerable GetAgentTools( var tcs = new TaskCompletionSource(); var meshService = Hub.ServiceProvider.GetRequiredService(); var workspace = Hub.GetWorkspace(); - var accessService = Hub.ServiceProvider.GetService(); - var subThreadId = ThreadNodeType.GenerateSpeakingId(task); + // Access context is restored by WrapToolWithAccessContext — no need to set it here. + var parentMsgPath = $"{execCtx.ThreadPath}/{execCtx.ResponseMessageId}"; - var subThreadPath = $"{parentMsgPath}/{subThreadId}"; + // MainNode for sub-thread = parent thread's MainNode (content node). + // ContextPath comes from the thread execution context which is set from + // the thread node's MainNode (e.g., "PartnerRe/AIConsulting"). + var mainEntityPath = execCtx.ContextPath ?? context ?? execCtx.ThreadPath; + + // Build sub-thread with pre-populated messages + var (subThreadNode, userMsgId, responseMsgId) = ThreadNodeType.BuildThreadWithMessages( + parentMsgPath, task, createdBy: execCtx.UserAccessContext?.ObjectId, + agentName: targetId); + subThreadNode = subThreadNode with { MainNode = mainEntityPath }; + var subThreadPath = subThreadNode.Path!; + + // Store delegation path keyed by display name for parallel-safe lookup. + var delegationDisplayName = $"Delegating to {targetId}..."; + chat.DelegationPaths[delegationDisplayName] = subThreadPath; + chat.LastDelegationPath = subThreadPath; + chat.UpdateDelegationStatus?.Invoke(delegationDisplayName); - // 1. Create sub-thread node (Observable — no await) - var mainEntityPath = context ?? execCtx.ContextPath ?? execCtx.ThreadPath; - var subThreadNode = new MeshNode(subThreadId, parentMsgPath) + // Create cells FIRST, then thread. WatchForExecution starts execution + // when it sees IsExecuting=true on the thread. + Logger.LogInformation("[Delegation] Creating cells for sub-thread {Path}: user={UserMsgId}, response={ResponseMsgId}", subThreadPath, userMsgId, responseMsgId); + meshService.CreateNode(new MeshNode(userMsgId, subThreadPath) { - Name = task.Length > 60 ? task[..57] + "..." : task, - NodeType = ThreadNodeType.NodeType, - MainNode = mainEntityPath, - Content = new MeshThread() - }; - - // Set delegation path and notify — the streaming loop is blocked - // during tool execution, so the throttle never fires. The callback - // pushes the tool call with DelegationPath immediately. - chat.LastDelegationPath = subThreadPath; - chat.UpdateDelegationStatus?.Invoke($"Delegating to {targetId}..."); + NodeType = ThreadMessageNodeType.NodeType, MainNode = mainEntityPath, + Content = new ThreadMessage + { + Role = "user", Text = task, Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.ExecutedInput, CreatedBy = execCtx.UserAccessContext?.ObjectId + } + }).Subscribe(_ => { }, error => Logger.LogError(error, "[Delegation] User cell creation failed for {Path}", subThreadPath)); + + meshService.CreateNode(new MeshNode(responseMsgId, subThreadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = mainEntityPath, + Content = new ThreadMessage + { + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse, AgentName = targetId + } + }).Subscribe(_ => { }, error => Logger.LogError(error, "[Delegation] Response cell creation failed for {Path}", subThreadPath)); + Logger.LogInformation("[Delegation] Creating sub-thread at {Path}", subThreadPath); meshService.CreateNode(subThreadNode).Subscribe( _ => { - Logger.LogInformation("[Delegation] Created sub-thread at {Path}", subThreadPath); - - // 2. Completion is notified via a second SubmitMessageResponse - // with Status=ExecutionCompleted, posted by ThreadExecution when done. - - // 3. Submit message (Post + RegisterCallback — no AwaitResponse) - var delivery = Hub.Post(new SubmitMessageRequest - { - ThreadPath = subThreadPath, - UserMessageText = task, - AgentName = targetId, - ContextPath = context ?? execCtx.ContextPath ?? execCtx.ThreadPath - }, o => - { - o = o.WithTarget(new Address(subThreadPath)); - if (execCtx.UserAccessContext != null) - o = o.WithAccessContext(execCtx.UserAccessContext); - return o; - }); + Logger.LogInformation("[Delegation] Sub-thread created at {Path}, watching for completion", subThreadPath); - if (delivery != null) + // Watch the sub-thread's state via ObserveQuery — when IsExecuting becomes false, delegation is done. + var meshSvc = Hub.ServiceProvider.GetService(); + bool IsComplete(QueryResultChange c) { - Hub.RegisterCallback((IMessageDelivery)delivery, response => - { - if (response is IMessageDelivery sr) + foreach (var n in c.Items) + if (n.Content is MeshThread { IsExecuting: false, PendingUserMessage: null }) + return true; + return false; + } + var filtered = System.Reactive.Linq.Observable.Where( + meshSvc!.ObserveQuery(MeshQueryRequest.FromQuery($"path:{subThreadPath}")), + IsComplete); + System.Reactive.Linq.Observable.Timeout( + System.Reactive.Linq.Observable.Take(filtered, 1), + TimeSpan.FromSeconds(30)) + .Subscribe( + change => { - var msg = sr.Message; - if (!msg.Success) + var node = change.Items.FirstOrDefault(); + var thread = node?.Content as MeshThread; + // Read the response from the response message cell + var responseText = $"Delegation to {targetId} completed."; + Logger.LogInformation("[Delegation] Completed: {Path}", subThreadPath); + tcs.TrySetResult(new DelegationResult { - Logger.LogWarning("[Delegation] Submit failed: {Error}", msg.Error); - tcs.TrySetResult(new DelegationResult - { - AgentName = targetId, Task = task, - Result = $"Submit failed: {msg.Error}", Success = false - }); - } - else if (msg.Status != SubmitMessageStatus.CellsCreated) + AgentName = targetId, Task = task, + Result = responseText, + Success = true, + ThreadId = subThreadPath + }); + }, + ex => + { + Logger.LogWarning(ex, "[Delegation] Watch failed for {Path}", subThreadPath); + tcs.TrySetResult(new DelegationResult { - // Execution completed/cancelled/failed — resolve delegation - Logger.LogInformation("[Delegation] Child finished: {Path}, status={Status}, textLen={TextLen}", - subThreadPath, msg.Status, msg.ResponseText?.Length ?? 0); - using var __ = accessService?.SwitchAccessContext(execCtx.UserAccessContext); - tcs.TrySetResult(new DelegationResult - { - AgentName = targetId, Task = task, - Result = msg.ResponseText ?? $"Delegation to {targetId} completed.", - Success = msg.Status == SubmitMessageStatus.ExecutionCompleted, - ThreadId = subThreadPath - }); - } - // CellsCreated = initial response, keep waiting for completion - } - return response; - }); - } + AgentName = targetId, Task = task, + Result = $"Delegation timed out: {ex.Message}", + Success = false, ThreadId = subThreadPath + }); + }); }, error => { - Logger.LogWarning(error, "[Delegation] Failed to create sub-thread for {Target}", targetId); + Logger.LogWarning(error, "[Delegation] Failed to create sub-thread at {Path} for {Target}, Hub={Hub}", subThreadPath, targetId, Hub.Address); tcs.TrySetResult(new DelegationResult { AgentName = targetId, Task = task, @@ -334,7 +422,18 @@ protected virtual IEnumerable GetAgentTools( }); }); - return tcs.Task; // AI framework awaits this — not our code + // Register cancellation to prevent infinite hang if sub-thread routing fails + cancellationToken.Register(() => + { + tcs.TrySetResult(new DelegationResult + { + AgentName = targetId, Task = task, + Result = $"Delegation to {targetId} was cancelled.", + Success = false + }); + }); + + return tcs.Task; }, Logger); @@ -502,3 +601,29 @@ Use handoff when the target agent should take over the conversation directly and return result; } } + +/// +/// AIFunction wrapper that restores the user's access context before each invocation. +/// This is the single injection point for ALL tool calls — delegation, MeshPlugin, etc. +/// +internal sealed class AccessContextAIFunction : DelegatingAIFunction +{ + private readonly IAgentChat _chat; + private readonly AccessService _accessService; + + public AccessContextAIFunction(AIFunction inner, IAgentChat chat, AccessService accessService) + : base(inner) + { + _chat = chat; + _accessService = accessService; + } + + protected override ValueTask InvokeCoreAsync( + AIFunctionArguments arguments, CancellationToken cancellationToken) + { + var userCtx = _chat.ExecutionContext?.UserAccessContext; + if (userCtx != null) + _accessService.SetContext(userCtx); + return base.InvokeCoreAsync(arguments, cancellationToken); + } +} diff --git a/src/MeshWeaver.AI/Data/Agent/Coder.md b/src/MeshWeaver.AI/Data/Agent/Coder.md index 666b86536..cba425421 100644 --- a/src/MeshWeaver.AI/Data/Agent/Coder.md +++ b/src/MeshWeaver.AI/Data/Agent/Coder.md @@ -307,6 +307,16 @@ For full examples, see: [Interactive Markdown](@@Doc/DataMesh/InteractiveMarkdow When asked to create an interactive document, create a Markdown node with the executable code blocks embedded. +# CRITICAL: You MUST write output + +**NEVER just describe what you would create. ALWAYS call Create, Update, or Patch to write the actual content.** If you didn't call a write tool, nothing was produced. The user expects to see a real node with real content after your work — not a description of what could be created. + +- Asked to create a Markdown document? → Call `Create` with the full markdown content. +- Asked to create a NodeType? → Call `Create` for each source file and the JSON definition. +- Asked to modify a node? → Call `Get` first, then `Update` with the modified content. + +**Every delegation MUST end with at least one write tool call.** + # Tools Use the standard Mesh tools (Get, Search, Create, Update, Delete) to manage nodes. diff --git a/src/MeshWeaver.AI/Data/Agent/CommentingReference.md b/src/MeshWeaver.AI/Data/Agent/CommentingReference.md index 53b881f7f..ba00b8cec 100644 --- a/src/MeshWeaver.AI/Data/Agent/CommentingReference.md +++ b/src/MeshWeaver.AI/Data/Agent/CommentingReference.md @@ -2,6 +2,7 @@ Name: Commenting Reference Category: Documentation Description: How to programmatically add comments and suggest edits on Markdown documents +Icon: --- ## Adding Comments diff --git a/src/MeshWeaver.AI/Data/Agent/Orchestrator.md b/src/MeshWeaver.AI/Data/Agent/Orchestrator.md index dc366d29f..70c3122f2 100644 --- a/src/MeshWeaver.AI/Data/Agent/Orchestrator.md +++ b/src/MeshWeaver.AI/Data/Agent/Orchestrator.md @@ -14,9 +14,9 @@ delegations: - agentPath: Agent/Researcher instructions: "Deep information gathering: web search, mesh exploration, data analysis, documentation lookup" - agentPath: Agent/Worker - instructions: "Execute actions: create, update, delete nodes. Schema discovery, verification, commenting" + instructions: "Execute write actions. Give EXACT instructions: which node path to read, what to change, and to call Patch. Example: 'Get @/path/node, update the Status section to reflect X, then Patch it back.' Worker MUST call Patch — if it didn't, the change did not happen." - agentPath: Agent/Versioning - instructions: "Version history: list versions, compare changes, restore to a specific version or point in time" + instructions: "ONLY when the user explicitly asks to see version history, compare versions, or restore/revert a node. Never delegate here proactively — do not check version history as preparation for updates." plugins: - Mesh - WebSearch @@ -40,17 +40,23 @@ You have ALL tools: Get, Search, NavigateTo, Create, Update, Delete, SearchWeb, 3. **Deep research** — Delegate to **Researcher** for thorough investigation across web and mesh. 4. **Keep text minimal** — Let tool results speak. A brief sentence after a tool call is enough. -# Namespace & Path Rules +# Path Rules -**When creating nodes, use the current context namespace.** Before creating, explore what exists: +**Paths are relative to the current context by default.** Absolute paths start with `/`. + +**In tool calls**, use relative paths when referring to things in the current context: +- `Get('@content:report.docx')` — file in current node's collection +- `Get('@MyChild/*')` — children of a child node +- `Get('@/OrgA/Doc')` — absolute path (starts with `/`) + +**In markdown output (links)**, ALWAYS use `@/` with the full absolute path so they are clickable: +- `@/PartnerRe/AIConsulting/100DayPlan` — correct, absolute path +- **NEVER** use bare relative names in response text — they won't resolve as links + +**When creating nodes**, use the current context namespace. Before creating, explore what exists: - `Search('namespace:{contextPath}')` — immediate children - `Search('namespace:{contextPath} scope:descendants')` — full directory tree -**When referencing nodes in your response text**, ALWAYS use `@` with the full absolute path: -- `@PartnerRe/AIConsulting/100DayPlan` — correct, absolute path -- **NEVER** use relative paths like `@my-node` — they won't resolve correctly -- These become clickable links in the UI automatically - Never create under `Agent/` or other system namespaces unless explicitly asked. # Tools Reference diff --git a/src/MeshWeaver.AI/Data/Agent/ToolsReference.md b/src/MeshWeaver.AI/Data/Agent/ToolsReference.md index 7583e5c27..8a9da58dc 100644 --- a/src/MeshWeaver.AI/Data/Agent/ToolsReference.md +++ b/src/MeshWeaver.AI/Data/Agent/ToolsReference.md @@ -2,15 +2,30 @@ Name: Tools Reference Category: Documentation Description: Complete tools reference for AI agents +Icon: --- MeshPlugin provides tools for interacting with the mesh data graph. All paths support the `@` prefix shorthand: `@graph/org1` resolves to `graph/org1`. **IMPORTANT**: Examples below use `Doc/Architecture` as a sample node path. Always use the actual node path from the user's context instead. -**LINKS**: Always output **absolute paths** starting with `@/` followed by the main partition and full path. Never use relative references. -- Correct: `@/OrgA/Projects/my-doc`, `@/User/rbuergi/my-page`, `@/Doc/Architecture` -- **Wrong**: `my-doc`, `../Projects/my-doc`, `Projects/my-doc` +## Path Rules + +**Tool calls use paths relative to the current context by default.** The "Current Application Context" tells you your current node path. + +- **Relative paths** (no leading `/`): resolved against your current context. When the user references a file or node they can see, use a relative path. + - `content:report.docx` → file in the current node's content collection + - `Get('@content:report.docx')` → get content from current node + - `Get('@MyChild/*')` → list children of a child node under current context +- **Absolute paths** (leading `/`): start from the root, independent of context. + - `Get('@/OrgA/Projects/my-doc')` → always resolves to the same node + - `Get('@/Doc/Architecture/content:icon.svg')` → file from a specific node + +**LINKS in markdown output**: Always use **absolute paths** starting with `@/` so they are clickable regardless of where the message is viewed. +- Correct: `@/OrgA/Projects/my-doc`, `@/User/rbuergi/my-page` +- **Wrong**: `my-doc`, `../Projects/my-doc` + +**When the user mentions a file or document they see on screen**, they are referring to something in the current context. Use the relative path (e.g., `content:filename.docx`), not a fully qualified absolute path. ## Get @@ -364,33 +379,39 @@ Use double @@ prefix to embed a layout area inline in markdown responses. Write ## Content Collections -Content collections store files (images, documents, markdown, etc.) associated with mesh nodes. The `content:` prefix accesses the default "content" collection. Other collection names use `collection:` for discovery. +Content collections store files (images, documents, markdown, etc.) associated with mesh nodes. The `content:` prefix accesses the default "content" collection. + +**Document conversion**: `.docx` files are automatically converted to markdown when accessed. The user can reference documents by name and get readable text. -### Workflow: Browsing and Downloading Files +### Accessing Files (Relative to Current Context) -When you need to work with files in a content collection, follow this sequence: +When the user references a file they see on screen, use the **relative** `content:` path: -1. **Discover collections**: `Get('@Doc/Architecture/collection:')` — lists all available collection configs (names, types, editability) -2. **List files in collection root**: `Get('@Doc/Architecture/content:')` — returns files and folders in the default "content" collection root -3. **List files in a named collection**: `Get('@Doc/Architecture/content:collectionName')` — returns files and folders in the named collection root -4. **Browse a subfolder**: `Get('@Doc/Architecture/content:collectionName/subfolder')` — if "subfolder" is a folder, returns its files and folders -5. **Download a specific file**: `Get('@Doc/Architecture/content:icon.svg')` — downloads the file from the default "content" collection -6. **Download from a subfolder**: `Get('@Doc/Architecture/content:MeshGraph/overview.svg')` — downloads a file from a subfolder +``` +Get('@content:report.docx') -- File from current node's "content" collection +Get('@content:subfolder/image.png') -- File from a subfolder +Get('@content:') -- List files in the current node's content root +Get('@collection:') -- List all collection configs +``` -The system automatically detects whether a path refers to a file or folder. Files are downloaded, folders are listed. Each item in a listing has `name`, `path`, `isFolder`, and `lastModified` (for files). +### Accessing Files (Absolute Path) -### Examples +For files on other nodes, use the full path: ``` -Get('@Doc/Architecture/collection:') -- List all collection configs -Get('@Doc/Architecture/content:') -- List files/folders in default "content" collection -Get('@Doc/Architecture/content:collectionName') -- List files/folders in a named collection -Get('@Doc/Architecture/content:collectionName/subfolder') -- List files in a subfolder -Get('@Doc/Architecture/content:icon.svg') -- Download icon.svg from default "content" collection -Get('@Doc/Architecture/content:MeshGraph/overview.svg') -- Download file from a subfolder +Get('@/Doc/Architecture/content:icon.svg') -- File from a specific node +Get('@/OrgA/content:report.docx') -- File from another org's node ``` -The format is: `@Doc/Architecture/content:{path}` where the path is automatically resolved as file (download) or folder (list contents). +### Document Support + +| Extension | Behavior | +|-----------|----------| +| `.docx` | Automatically converted to markdown | +| `.md` | Returned as-is | +| `.pdf`, `.png`, `.jpg` | Returned as binary content | + +When the user asks about a document they uploaded or see in the file browser, use `Get('@content:filename.docx')` to read its content as markdown. ### Embedding Content Files @@ -452,3 +473,34 @@ To browse all available documentation: Search('namespace:Doc scope:descendants') ``` Then read any article with `Get('@Doc/...')`. + +## Binary Attachments (PDF, Images) + +Chat threads support binary file attachments from content collections. When a `content:` path references a binary file, it is sent to the AI model as native binary content (base64). + +### Supported Binary Formats + +| Extension | MIME Type | Sent As | +|-----------|-----------|---------| +| `.pdf` | `application/pdf` | Document block (Claude analyzes text + layout) | +| `.png` | `image/png` | Image block | +| `.jpg`/`.jpeg` | `image/jpeg` | Image block | +| `.gif` | `image/gif` | Image block | +| `.webp` | `image/webp` | Image block | + +### Attachment Path Resolution + +- **Relative** (no `/` prefix): `content:report.pdf` → resolved against thread's context path +- **Absolute** (`/` prefix): `@/OrgA/Doc/content:report.pdf` → explicit path from root + +### Delegation + +Delegation creates an isolated sub-thread for a target agent. The delegation tool: +1. Creates a Thread node under the parent message +2. Posts `SubmitMessageRequest` to the sub-thread +3. Waits for `ExecutionCompleted` response via callback re-registration +4. Returns the result to the parent agent + +**Depth limit**: Maximum 2 delegation levels to prevent infinite recursion. + +**Identity**: All tool calls run with the original user's identity, restored via `AccessContextAIFunction` wrapper. diff --git a/src/MeshWeaver.AI/Data/Agent/Worker.md b/src/MeshWeaver.AI/Data/Agent/Worker.md index 00f0daddf..cfe061d9b 100644 --- a/src/MeshWeaver.AI/Data/Agent/Worker.md +++ b/src/MeshWeaver.AI/Data/Agent/Worker.md @@ -13,21 +13,35 @@ plugins: - ContentCollection delegations: - agentPath: Agent/Versioning - instructions: "Version history: list versions, compare changes, restore to a specific version or point in time" + instructions: "ONLY when the user explicitly asks to see version history, compare versions, or restore/revert a node. Never delegate here proactively." --- You are **Worker**, the action agent. You execute tasks using all available tools including write operations. Be direct, efficient, and always verify your work. -# Namespace & Path Rules +**CRITICAL: You MUST produce output.** Every task MUST end with at least one write tool call (Create, Update, or Patch). If you didn't call a write tool, you produced nothing. Never describe what you would create — call the tool and create it. -**When creating nodes, use the namespace from your task context or the "Current Application Context".** Before creating, explore what exists: +**MANDATORY WORKFLOW — read, adapt, write:** +1. `Get` the target node (1 call — not multiple). If you need a reference doc, get it too (max 2 Get calls total). +2. Build the updated content in your head. Do NOT output it as text. +3. Call `Patch` with the adapted content immediately. This is the ONLY output that matters. +4. If Patch fails, report the error. Do NOT describe what you "would have written." + +**FORBIDDEN:** Calling Get on more than 3 nodes. Describing changes without calling Patch. Saying "the document is already complete." Ending without a write tool call. + +# Path Rules + +**Paths are relative to the current context by default.** Absolute paths start with `/`. + +**In tool calls**, use relative paths for things in the current context: +- `Get('@content:report.docx')` — file in current node's collection +- `Get('@/OrgA/Doc')` — absolute path (starts with `/`) + +**In markdown output (links)**, ALWAYS use `@/` with the full absolute path so they become clickable. + +**When creating nodes**, use the namespace from your task context. Before creating, explore what exists: - `Search('namespace:{contextPath}')` — immediate children - `Search('namespace:{contextPath} scope:descendants')` — full directory tree -**When referencing nodes in your response**, ALWAYS use `@` with the full absolute path so they become clickable: -- `@PartnerRe/AIConsulting/100DayPlan` — correct, absolute path -- **NEVER** use relative paths like `@my-node` — they won't resolve correctly - Never create under `Agent/` or other system namespaces unless explicitly asked. # Tools Reference @@ -101,7 +115,8 @@ To find satellites: `Search('namespace:{parentPath}/_Thread nodeType:Thread')` # Guidelines - Be direct — execute tasks without unnecessary deliberation -- Always verify after write operations: "Created X", "Updated Y", "Deleted Z" +- **ALWAYS write back.** When asked to update a node: `Get` it, modify it, then call `Update` or `Patch`. If you did not call Update/Patch, the change did NOT happen. Never just describe what you changed — call the tool. +- Always verify after write operations: `Get` the node to confirm it was saved correctly - If a step fails, report the error — do not retry blindly - Use SearchWeb/FetchWebPage for external information when needed - Discover schemas before creating or updating nodes diff --git a/src/MeshWeaver.AI/IAgentChat.cs b/src/MeshWeaver.AI/IAgentChat.cs index f5cb7d972..f19c7c13a 100644 --- a/src/MeshWeaver.AI/IAgentChat.cs +++ b/src/MeshWeaver.AI/IAgentChat.cs @@ -77,9 +77,17 @@ void RequestHandoff(HandoffRequest request) { } /// /// Path of the last delegation sub-thread created. Consumed by ThreadExecution /// after each delegation tool call completes. + /// Deprecated: use DelegationPaths dictionary for parallel-safe delegation tracking. /// string? LastDelegationPath { get => null; set { } } + /// + /// Thread-safe mapping of delegation display name to sub-thread path. + /// Supports parallel delegations without race conditions. + /// + System.Collections.Concurrent.ConcurrentDictionary DelegationPaths + => new(); + /// /// Callback to update delegation status on the parent execution context. /// Set by ThreadExecution, called by delegation tools to forward sub-agent progress. @@ -92,4 +100,11 @@ void RequestHandoff(HandoffRequest request) { } /// Action? ForwardToolCall { get => null; set { } } + /// + /// Callback to forward node change entries from MeshOperations (Create/Update/Patch). + /// Set by ThreadExecution, invoked by MeshPlugin when nodes are modified. + /// Tracks path + version before/after for document change auditing per thread message. + /// + Action? ForwardNodeChange { get => null; set { } } + } diff --git a/src/MeshWeaver.AI/InternalsVisibleTo.cs b/src/MeshWeaver.AI/InternalsVisibleTo.cs new file mode 100644 index 000000000..05f116a95 --- /dev/null +++ b/src/MeshWeaver.AI/InternalsVisibleTo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("MeshWeaver.Threading.Test")] +[assembly: InternalsVisibleTo("MeshWeaver.Hosting.Orleans.Test")] diff --git a/src/MeshWeaver.AI/Layout/ThreadsLayoutArea.cs b/src/MeshWeaver.AI/Layout/ThreadsLayoutArea.cs deleted file mode 100644 index 6f049a4fc..000000000 --- a/src/MeshWeaver.AI/Layout/ThreadsLayoutArea.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.ComponentModel; -using MeshWeaver.Layout; -using MeshWeaver.Layout.Composition; -using MeshWeaver.Messaging; - -namespace MeshWeaver.AI.Layout; - -/// -/// Layout area for displaying node-scoped threads. -/// Registers the Threads view that displays thread history for a node. -/// Uses MeshSearchControl with reactive mode for automatic updates. -/// -public static class ThreadsLayoutArea -{ - public const string ThreadsArea = "Threads"; - - /// - /// Adds the Threads view to the layout. - /// Call this after AddDefaultLayoutAreas() to register the Threads area. - /// - public static LayoutDefinition AddThreadsLayoutArea(this LayoutDefinition layout) - => layout.WithView(ThreadsArea, Threads); - - /// - /// Adds the Threads view to the hub's layout configuration. - /// - public static MessageHubConfiguration AddThreadsLayoutArea(this MessageHubConfiguration configuration) - => configuration.AddLayout(layout => layout.AddThreadsLayoutArea()); - - /// - /// Renders the Threads area showing node-scoped thread history. - /// Uses MeshSearchControl for thread discovery sorted by last activity. - /// - [Browsable(false)] - public static UiControl Threads(LayoutAreaHost host, RenderingContext _) - { - var nodePath = host.Hub.Address.ToString(); - - return Controls.MeshSearch - .WithHiddenQuery($"nodeType:Thread namespace:{nodePath}/{ThreadNodeType.ThreadPartition}") - .WithNamespace(nodePath) - .WithRenderMode(MeshSearchRenderMode.Flat) - .WithCreateNodeType("Thread"); - } -} diff --git a/src/MeshWeaver.AI/MeshOperations.cs b/src/MeshWeaver.AI/MeshOperations.cs index a22ae6c7a..ad682bda2 100644 --- a/src/MeshWeaver.AI/MeshOperations.cs +++ b/src/MeshWeaver.AI/MeshOperations.cs @@ -3,6 +3,7 @@ using System.Text.Json.Nodes; using System.Text.Json.Schema; using MeshWeaver.Data; +using MeshWeaver.Layout; using MeshWeaver.Domain; using MeshWeaver.Mesh; using MeshWeaver.Mesh.Services; @@ -22,6 +23,12 @@ public class MeshOperations private readonly ILogger logger; private readonly IMeshService mesh; + /// + /// Callback invoked when a node is created, updated, or patched. + /// Provides path and version before/after for tracking document changes per thread message. + /// + public Action? OnNodeChange { get; set; } + public MeshOperations(IMessageHub hub) { this.hub = hub; @@ -206,7 +213,19 @@ public async Task Create(string node) var tcs = new TaskCompletionSource(); mesh.CreateNode(meshNode).Subscribe( - created => tcs.TrySetResult($"Created: {created.Path}"), + created => + { + OnNodeChange?.Invoke(new NodeChangeEntry + { + Path = created.Path, + Operation = "Created", + VersionBefore = null, + VersionAfter = created.Version, + NodeType = created.NodeType, + NodeName = created.Name + }); + tcs.TrySetResult($"Created: {created.Path}"); + }, ex => tcs.TrySetResult($"Error creating node: {ex.Message}")); return await tcs.Task; } @@ -247,9 +266,22 @@ public async Task Update(string nodes) continue; } + var versionBefore = meshNode.Version; var updateTcs = new TaskCompletionSource(); mesh.UpdateNode(meshNode).Subscribe( - updated => updateTcs.TrySetResult($"Updated: {updated.Path}"), + updated => + { + OnNodeChange?.Invoke(new NodeChangeEntry + { + Path = updated.Path, + Operation = "Updated", + VersionBefore = versionBefore, + VersionAfter = updated.Version, + NodeType = updated.NodeType, + NodeName = updated.Name + }); + updateTcs.TrySetResult($"Updated: {updated.Path}"); + }, ex => updateTcs.TrySetResult($"Error updating {meshNode.Path}: {ex.Message}")); results = results.Add(await updateTcs.Task); } @@ -297,9 +329,22 @@ public async Task Patch(string path, string fields) PreRenderedHtml = jsonObj.ContainsKey("preRenderedHtml") ? partial.PreRenderedHtml : existing.PreRenderedHtml, }; + var versionBefore = existing.Version; var patchTcs = new TaskCompletionSource(); mesh.UpdateNode(merged).Subscribe( - updated => patchTcs.TrySetResult($"Patched: {updated.Path}"), + updated => + { + OnNodeChange?.Invoke(new NodeChangeEntry + { + Path = updated.Path, + Operation = "Updated", + VersionBefore = versionBefore, + VersionAfter = updated.Version, + NodeType = updated.NodeType, + NodeName = updated.Name + }); + patchTcs.TrySetResult($"Patched: {updated.Path}"); + }, ex => patchTcs.TrySetResult($"Error patching {merged.Path}: {ex.Message}")); return await patchTcs.Task; } diff --git a/src/MeshWeaver.AI/MeshPlugin.cs b/src/MeshWeaver.AI/MeshPlugin.cs index 8bef8e975..6bfb9847d 100644 --- a/src/MeshWeaver.AI/MeshPlugin.cs +++ b/src/MeshWeaver.AI/MeshPlugin.cs @@ -10,22 +10,23 @@ namespace MeshWeaver.AI; /// /// Plugin providing mesh operations for AI agents. /// Thin wrapper over MeshOperations with AITool factory and layout-based NavigateTo. +/// Resolves relative paths against the current chat context. /// public class MeshPlugin(IMessageHub hub, IAgentChat chat) { - private readonly MeshOperations ops = new(hub); + private readonly MeshOperations ops = new(hub) { OnNodeChange = change => chat.ForwardNodeChange?.Invoke(change) }; private readonly ILogger logger = hub.ServiceProvider.GetRequiredService>(); - [Description("Retrieves a node or content from the mesh by path. Supports Unified Path prefixes (schema:, model:, data:, content:, collection:, area:, layoutAreas:).")] + [Description("Retrieves a node or content from the mesh by path. Paths are relative to current context; use @/ prefix for absolute paths. Supports Unified Path prefixes (schema:, model:, data:, content:, collection:, area:, layoutAreas:).")] public Task Get( - [Description("Path to data (e.g., @graph/org1, @NodeType/*, @ACME/schema:, @ACME/model:)")] string path) - => ops.Get(path); + [Description("Path to data. Relative: @content:file.docx, @MyChild/*. Absolute: @/OrgA/Doc, @/OrgA/content:file.docx")] string path) + => ops.Get(ResolveContextPath(path)); [Description("Searches the mesh using GitHub-style query syntax.")] public Task Search( [Description("Query string (e.g., 'nodeType:Agent', 'path:ACME scope:descendants', 'name:*sales*')")] string query, [Description("Base path to search from (e.g., @graph). Empty for all.")] string? basePath = null) - => ops.Search(query, basePath); + => ops.Search(query, basePath != null ? ResolveContextPath(basePath) : null); [Description("Creates a new node in the mesh. ALWAYS set the 'name' property to a human-readable display name.")] public Task Create( @@ -41,7 +42,7 @@ public Task Update( public Task Patch( [Description("Path to the node (e.g., @User/rbuergi/my-node)")] string path, [Description("JSON object with only the fields to update (e.g., {\"icon\": \"...\"} or {\"name\": \"New Name\", \"content\": {...}})")] string fields) - => ops.Patch(path, fields); + => ops.Patch(ResolveContextPath(path), fields); [Description("Deletes nodes from the mesh by path.")] public Task Delete( @@ -54,7 +55,7 @@ public string NavigateTo( { logger.LogInformation("NavigateTo called with path={Path}", path); - var resolvedPath = MeshOperations.ResolvePath(path); + var resolvedPath = MeshOperations.ResolvePath(ResolveContextPath(path)); var address = new Address(resolvedPath); var layoutControl = Controls.LayoutArea(address, string.Empty); @@ -62,6 +63,52 @@ public string NavigateTo( return $"Navigating to: {resolvedPath}"; } + /// + /// Resolves a path relative to the current chat context. + /// Absolute paths (starting with @/ or /) are returned as-is. + /// Relative paths (e.g., @content:file.docx, @MyChild) are prepended with context path. + /// + private string ResolveContextPath(string path) + { + if (string.IsNullOrEmpty(path)) + return path; + + var raw = path.StartsWith("@") ? path[1..] : path; + + // Absolute path — starts with / + if (raw.StartsWith("/")) + return "@" + raw[1..]; // strip the leading / and re-add @ + + // Already looks absolute (contains a colon with address before it, like OrgA/content:file) + // Check if this is a unified path with address prefix + var colonIndex = raw.IndexOf(':'); + if (colonIndex > 0) + { + var beforeColon = raw[..colonIndex]; + // If there's a slash before the colon, it has an address prefix already + if (beforeColon.Contains('/')) + return path; // already absolute + } + else if (raw.Contains('/')) + { + // No colon, has slashes — could be a multi-segment path like "OrgA/Doc" + // If it has 2+ segments, likely absolute already + return path; + } + + // Relative path — prepend context + var contextPath = chat.Context?.Context; + if (string.IsNullOrEmpty(contextPath)) + return path; // no context, return as-is + + // For unified refs like "content:file.docx", prepend context as address + if (colonIndex > 0) + return $"@{contextPath}/{raw}"; + + // For simple names like "MyChild", prepend context + return $"@{contextPath}/{raw}"; + } + /// /// Creates the standard tools for this plugin (read-only operations). /// diff --git a/src/MeshWeaver.AI/SubmitMessageRequest.cs b/src/MeshWeaver.AI/SubmitMessageRequest.cs index bc6a6b7c7..f6e6c7ce2 100644 --- a/src/MeshWeaver.AI/SubmitMessageRequest.cs +++ b/src/MeshWeaver.AI/SubmitMessageRequest.cs @@ -21,11 +21,19 @@ public record SubmitMessageRequest : IRequest public string? ContextPath { get; init; } public IReadOnlyList? Attachments { get; init; } + /// + /// Client-generated IDs for optimistic rendering. + /// If set, the server uses these instead of generating its own. + /// + public string? UserMessageId { get; init; } + public string? ResponseMessageId { get; init; } + /// /// Set by HandleSubmitMessage after creating the response node. /// The execution hub uses this to post streaming progress updates. /// public string? ResponsePath { get; init; } + } /// @@ -51,6 +59,18 @@ public record SubmitMessageResponse public string? Error { get; init; } public SubmitMessageStatus Status { get; init; } = SubmitMessageStatus.CellsCreated; public string? ResponseText { get; init; } + + /// + /// Node changes made during this thread's execution. + /// Propagated upward so parent threads can aggregate changes from delegations. + /// + public System.Collections.Immutable.ImmutableList? UpdatedNodes { get; init; } + + /// + /// Full Messages list after cells are created. Sent with CellsCreated so the client + /// can render LayoutAreaViews immediately without waiting for the workspace stream. + /// + public IReadOnlyList? Messages { get; init; } } public enum SubmitMessageStatus diff --git a/src/MeshWeaver.AI/Thread.cs b/src/MeshWeaver.AI/Thread.cs index f420fde4d..edd0074e6 100644 --- a/src/MeshWeaver.AI/Thread.cs +++ b/src/MeshWeaver.AI/Thread.cs @@ -1,11 +1,13 @@ using System.Collections.Immutable; using System.Text.Json; +using System.Text.Json.Serialization; using MeshWeaver.Layout; using MeshWeaver.Messaging; using MeshWeaver.ShortGuid; namespace MeshWeaver.AI; + /// /// Tracks execution context for delegation sub-thread creation. /// Set by ThreadExecution, consumed by delegation tools. @@ -119,15 +121,32 @@ public record Thread public DateTime? ExecutionStartedAt { get; init; } /// - /// Streaming text buffer — updated at 2/sec during execution on the Thread node (local workspace). - /// Cleared when execution completes (final text is persisted on the response message). + /// Streaming text buffer — transient, never persisted. + /// Used only in-memory during active execution for the status bar preview. /// - public string? StreamingText { get; init; } - /// - /// Streaming tool calls — updated at 2/sec during execution. - /// Cleared when execution completes. + /// Pending user message text — set at thread creation to auto-start execution. + /// When the thread grain activates and sees this, it immediately starts streaming. + /// Cleared after execution starts. /// + public string? PendingUserMessage { get; init; } + + /// Agent name for pending execution. + public string? PendingAgentName { get; init; } + + /// Model name for pending execution. + public string? PendingModelName { get; init; } + + /// Context path for pending execution. + public string? PendingContextPath { get; init; } + + /// Attachments for pending execution. + public IReadOnlyList? PendingAttachments { get; init; } + + [JsonIgnore] + public string? StreamingText { get; init; } + + [JsonIgnore] public ImmutableList? StreamingToolCalls { get; init; } } @@ -159,11 +178,6 @@ public static class ThreadMessageExtensions /// public record ThreadMessage { - /// - /// Unique identifier for this message. - /// - public required string Id { get; init; } - /// /// The role of the message sender: "user", "assistant", or "system". /// @@ -184,11 +198,6 @@ public record ThreadMessage /// public DateTime Timestamp { get; init; } = DateTime.UtcNow; - /// - /// If this message triggered a delegation, path to the sub-thread node. - /// - public string? DelegationPath { get; init; } - /// /// The type of this message for rendering purposes. /// Defaults to ExecutedInput for backward compatibility. @@ -217,9 +226,9 @@ public record ThreadMessage public ImmutableList ToolCalls { get; init; } = []; /// - /// MeshNode changes made during this message's execution. - /// Tracks path, operation (Created/Updated/Deleted), and version before/after - /// so the version repo can load content at each point. + /// Nodes created or updated during this message's execution. + /// Tracks path and version before/after so the UI can show + /// which documents were written and the version delta. /// - public ImmutableList NodeChanges { get; init; } = []; + public ImmutableList UpdatedNodes { get; init; } = []; } diff --git a/src/MeshWeaver.AI/ThreadExecution.cs b/src/MeshWeaver.AI/ThreadExecution.cs index 92f5f6801..d0eddf579 100644 --- a/src/MeshWeaver.AI/ThreadExecution.cs +++ b/src/MeshWeaver.AI/ThreadExecution.cs @@ -1,7 +1,9 @@ -using System.Collections.Immutable; +using System.Collections.Concurrent; +using System.Collections.Immutable; using System.Reactive.Linq; using System.Text; using System.Text.Json; +using MeshWeaver.AI.Plugins; using MeshWeaver.Data; using MeshWeaver.Graph; using MeshWeaver.Layout; @@ -25,11 +27,41 @@ public static class ThreadExecution /// Registers thread execution handlers on a hub configuration. /// Includes a startup recovery check for stale executing cells from crashed sessions. /// + /// + /// Stores completion callbacks keyed by thread path. + /// Used to route ExecutionCompleted responses from the _Exec hub + /// back to the original client delivery on the thread hub. + /// Safe: thread hub + _Exec hub always run on the same grain/process. + /// + private static readonly ConcurrentDictionary> CompletionCallbacks = new(); + private static readonly ConcurrentDictionary ExecutionCancellations = new(); + private static readonly ConcurrentDictionary AgentCache = new(); + public static MessageHubConfiguration AddThreadExecution(this MessageHubConfiguration configuration) => configuration .WithHandler(HandleSubmitMessage) .WithHandler(HandleCancelStream) - .WithInitialization(RecoverStaleExecutingThread); + .WithInitialization(SetThreadHubIdentity) + .WithInitialization(RecoverStaleExecutingThread) + .WithInitialization(WatchForExecution); + + /// + /// Sets the thread hub's access context to the thread creator's identity. + /// Without this, the hub's default identity is its own address path, + /// causing "Access denied" when reading child message nodes. + /// + private static Task SetThreadHubIdentity(IMessageHub hub, CancellationToken ct) + { + hub.GetWorkspace().GetStream(new MeshNodeReference())?.Take(1).Subscribe(node => + { + if (node.Value?.Content is MeshThread { CreatedBy: { Length: > 0 } createdBy }) + { + var accessService = hub.ServiceProvider.GetService(); + accessService?.SetContext(new AccessContext { ObjectId = createdBy, Name = createdBy }); + } + }); + return Task.CompletedTask; + } /// /// On hub startup, check if this Thread was left in IsExecuting=true state (crashed/restarted). @@ -50,23 +82,36 @@ private static Task RecoverStaleExecutingThread(IMessageHub hub, CancellationTok if (threadNode?.Content is not Thread { IsExecuting: true } thread) return; + // Don't recover fresh executions — WatchForExecution handles them. + // Only recover truly stale ones (started > 2 minutes ago or no timestamp). + if (thread.ExecutionStartedAt is { } startedAt && + (DateTime.UtcNow - startedAt).TotalMinutes < 2) + { + logger?.LogInformation("[ThreadExec] Recovery: skipping fresh execution on {ThreadPath} (started {StartedAt})", threadPath, startedAt); + return; + } + logger?.LogInformation("[ThreadExec] Recovery: stale execution on {ThreadPath}, activeMsg={ActiveMsg}", threadPath, thread.ActiveMessageId); - // Cancel pending tool calls on the active response message + // Cancel pending tool calls on the active response message. + // For delegation tool calls, check if the sub-thread actually completed. if (!string.IsNullOrEmpty(thread.ActiveMessageId)) { var responsePath = $"{threadPath}/{thread.ActiveMessageId}"; - // Mark all pending tool calls as cancelled - var cancelledToolCalls = thread.StreamingToolCalls? - .Select(tc => tc.Result == null - ? tc with { Result = "Cancelled (server restarted)", IsSuccess = false } - : tc) + + // Mark all pending tool calls as cancelled — no query needed. + // Sub-thread recovery happens independently on their own hub init. + var updatedToolCalls = thread.StreamingToolCalls? + .Select(tc => tc.Result != null + ? tc + : tc with { Result = "Cancelled (server restarted)", IsSuccess = false }) .ToImmutableList(); + hub.Post(new UpdateThreadMessageContent { Text = "*Cancelled (server restarted)*", - ToolCalls = cancelledToolCalls + ToolCalls = updatedToolCalls }, o => o.WithTarget(new Address(responsePath))); } @@ -97,12 +142,124 @@ private static Task RecoverStaleExecutingThread(IMessageHub hub, CancellationTok return Task.CompletedTask; } + /// + /// On hub startup, check if this Thread has a PendingUserMessage. + /// If so, create message cells and start execution automatically. + /// This enables thread creation + execution in a single CreateNodeRequest. + /// + /// + /// Watches the workspace stream for IsExecuting=true with ActiveMessageId. + /// When detected, starts execution on the _Exec hosted hub. + /// This is the ONLY trigger for execution — state-driven, not command-driven. + /// GUI sets IsExecuting=true via SubmitMessageRequest → execution starts automatically. + /// + /// + /// Watches for auto-execute threads (created with BuildThreadWithMessages). + /// These threads have PendingUserMessage set at creation time (not via HandleSubmitMessage). + /// Creates message cells and starts execution on hub startup. + /// HandleSubmitMessage handles all client-initiated execution directly. + /// + private static Task WatchForExecution(IMessageHub hub, CancellationToken ct) + { + var logger = hub.ServiceProvider.GetService>(); + var workspace = hub.GetWorkspace(); + var threadPath = hub.Address.Path; + + // Only check on startup (Take(1)) — HandleSubmitMessage handles runtime execution. + workspace.GetStream(new MeshNodeReference())?.Take(1).Subscribe(node => + { + if (node.Value?.Content is not MeshThread { PendingUserMessage: not null } thread) + return; + + // Only auto-execute threads created with BuildThreadWithMessages + if (!thread.IsExecuting || thread.ActiveMessageId == null) + return; + + var responseMsgId = thread.ActiveMessageId; + var responsePath = $"{threadPath}/{responseMsgId}"; + var activeIdx = thread.Messages.IndexOf(responseMsgId); + var userMsgId = activeIdx > 0 ? thread.Messages[activeIdx - 1] : null; + // MainNode for child cells = the thread's own MainNode (content node). + var mainEntity = node.Value?.MainNode ?? thread.PendingContextPath ?? threadPath; + + logger?.LogInformation("[ThreadExec] Auto-execute: {ThreadPath}, activeMsg={ActiveMsg}", + threadPath, responseMsgId); + + var accessService = hub.ServiceProvider.GetService(); + if (!string.IsNullOrEmpty(thread.CreatedBy)) + accessService?.SetContext(new AccessContext { ObjectId = thread.CreatedBy, Name = thread.CreatedBy }); + + var userCtx = !string.IsNullOrEmpty(thread.CreatedBy) + ? new AccessContext { ObjectId = thread.CreatedBy, Name = thread.CreatedBy } + : null; + + void StartExecution() + { + hub.Post(new UpdateThreadMessageContent { Text = "Allocating agent..." }, + o => o.WithTarget(new Address(responsePath))); + + var executionHub = hub.GetHostedHub( + new Address($"{hub.Address}/_Exec"), + config => config.WithHandler(ExecuteMessageAsync), + HostedHubCreation.Always); + + executionHub!.Post(new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = thread.PendingUserMessage ?? "", + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId, + ResponsePath = responsePath, + AgentName = thread.PendingAgentName, + ModelName = thread.PendingModelName, + ContextPath = thread.PendingContextPath ?? thread.CreatedBy, + Attachments = thread.PendingAttachments + }, o => userCtx != null ? o.WithAccessContext(userCtx) : o); + } + + // Create cells, then start execution + var meshService = hub.ServiceProvider.GetRequiredService(); + meshService.CreateNode(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = mainEntity, + Content = new ThreadMessage + { + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse, + AgentName = thread.PendingAgentName, ModelName = thread.PendingModelName + } + }).Subscribe(_ => StartExecution(), + error => + { + logger?.LogDebug("[ThreadExec] Response cell creation error: {Error}", error.Message); + StartExecution(); + }); + + if (userMsgId != null) + { + meshService.CreateNode(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = mainEntity, + Content = new ThreadMessage + { + Role = "user", Text = thread.PendingUserMessage, Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.ExecutedInput, CreatedBy = thread.CreatedBy + } + }).Subscribe(_ => { }, + error => logger?.LogDebug("[ThreadExec] User cell creation error: {Error}", error.Message)); + } + }); + + return Task.CompletedTask; + } /// - /// Handles SubmitMessageRequest on the thread hub. - /// 1) Create input + output cells concurrently - /// 2) On success: update Thread.ThreadMessages via stream, start execution - /// 3) On failure: respond with error + /// Handles SubmitMessageRequest: updates thread state, responds immediately, + /// then starts execution. + /// - GUI flow (client provides UserMessageId + ResponseMessageId): cells already exist, + /// start execution directly. + /// - Server flow (no IDs provided): set PendingUserMessage so WatchForExecution + /// creates cells and starts execution. /// internal static IMessageDelivery HandleSubmitMessage( IMessageHub hub, @@ -111,100 +268,126 @@ internal static IMessageDelivery HandleSubmitMessage( var request = delivery.Message; var threadPath = request.ThreadPath; var logger = hub.ServiceProvider.GetService>(); - logger?.LogDebug("[ThreadExec] HandleSubmitMessage: threadPath={ThreadPath}, user={User}, hubAddress={Hub}", - threadPath, request.ContextPath, hub.Address); - var meshService = hub.ServiceProvider.GetRequiredService(); - var userMsgId = Guid.NewGuid().ToString("N")[..8]; - var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + var clientProvidedCells = request.UserMessageId != null && request.ResponseMessageId != null; + var userMsgId = request.UserMessageId ?? Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = request.ResponseMessageId ?? Guid.NewGuid().ToString("N")[..8]; var responsePath = $"{threadPath}/{responseMsgId}"; - logger?.LogDebug("[ThreadExec] Creating cells: userMsg={UserMsgId}, responseMsg={ResponseMsgId}", - userMsgId, responseMsgId); - // Capture workspace BEFORE Subscribe — inside Subscribe callback, hub context may differ - var threadWorkspace = hub.GetWorkspace(); - - // MainNode = content entity (e.g., "PartnerRe/AiConsulting"), not a thread path. - // This is critical for access control — all satellite nodes must reference the main entity. - var mainEntity = request.ContextPath ?? threadPath; - - // 1) Create both cells concurrently via Observable. - // CreateNode captures AccessContext eagerly at call time (inside the delivery - // pipeline where it's set from delivery.AccessContext). No explicit identity needed. - var inputObs = meshService.CreateNode(new MeshNode(userMsgId, threadPath) + // Update Thread state. Set PendingUserMessage so WatchForExecution + // creates cells when they don't exist (server flow, delegation flow). + hub.GetWorkspace().UpdateMeshNode(node => { - NodeType = ThreadMessageNodeType.NodeType, - MainNode = mainEntity, - Content = new ThreadMessage + var thread = node.Content as MeshThread ?? new MeshThread(); + var msgs = thread.Messages; + if (!msgs.Contains(userMsgId)) msgs = msgs.Add(userMsgId); + if (!msgs.Contains(responseMsgId)) msgs = msgs.Add(responseMsgId); + return node with { - Id = userMsgId, - Role = "user", - Text = request.UserMessageText, - Timestamp = DateTime.UtcNow, - Type = ThreadMessageType.ExecutedInput, - CreatedBy = delivery.AccessContext?.ObjectId - } + Content = thread with + { + Messages = msgs, + IsExecuting = true, + ActiveMessageId = responseMsgId, + ExecutionStatus = null, + TokensUsed = 0, + ExecutionStartedAt = DateTime.UtcNow, + PendingUserMessage = request.UserMessageText, + PendingAgentName = request.AgentName, + PendingModelName = request.ModelName, + PendingContextPath = request.ContextPath, + PendingAttachments = request.Attachments?.ToImmutableList() + } + }; }); - var outputObs = meshService.CreateNode(new MeshNode(responseMsgId, threadPath) + logger?.LogInformation("[ThreadExec] HandleSubmitMessage: state updated for {ThreadPath}, activeMsg={ActiveMsg}, clientCells={ClientCells}", + threadPath, responseMsgId, clientProvidedCells); + + var userCtx = delivery.AccessContext; + // MainNode for child cells = the thread's own MainNode (content node, e.g. "PartnerRe/AIConsulting"). + // Fall back to request.ContextPath, then threadPath. Read from the workspace to get the + // thread node's actual MainNode — this is authoritative, not the client's ContextPath. + var threadNode = hub.GetWorkspace().GetStream(new MeshNodeReference())?.Current?.Value; + var mainEntity = threadNode?.MainNode ?? request.ContextPath ?? threadPath; + + void RespondAndStartExecution() { - NodeType = ThreadMessageNodeType.NodeType, - MainNode = mainEntity, - Content = new ThreadMessage + hub.Post(new SubmitMessageResponse { Success = true, Messages = ImmutableList.Create(userMsgId, responseMsgId) }, + o => o.ResponseFor(delivery)); + + hub.Post(new UpdateThreadMessageContent { Text = "Allocating agent..." }, + o => o.WithTarget(new Address(responsePath))); + + var executionHub = hub.GetHostedHub( + new Address($"{hub.Address}/_Exec"), + config => config.WithHandler(ExecuteMessageAsync), + HostedHubCreation.Always); + + executionHub!.Post(new SubmitMessageRequest { - Id = responseMsgId, - Role = "assistant", - Text = "", - Timestamp = DateTime.UtcNow, - Type = ThreadMessageType.AgentResponse, + ThreadPath = threadPath, + UserMessageText = request.UserMessageText, + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId, + ResponsePath = responsePath, AgentName = request.AgentName, - ModelName = request.ModelName - } - }); + ModelName = request.ModelName, + ContextPath = request.ContextPath, + Attachments = request.Attachments + }, o => userCtx != null ? o.WithAccessContext(userCtx) : o); + } - inputObs.Zip(outputObs).Subscribe( - pair => + void RespondWithError(string error) + { + logger?.LogWarning("[ThreadExec] Cell creation failed for {ThreadPath}: {Error}", threadPath, error); + // Clear execution state since we're not starting + hub.GetWorkspace().UpdateMeshNode(node => { - logger?.LogInformation("HandleSubmitMessage: cells created for {ThreadPath}", threadPath); - - // 2) Update Thread: add message IDs and set execution state - threadWorkspace.UpdateMeshNode(node => - { - var thread = node.Content as MeshThread ?? new MeshThread(); - return node with - { - Content = thread with - { - Messages = thread.Messages.AddRange([userMsgId, responseMsgId]), - IsExecuting = true, - ActiveMessageId = responseMsgId, - ExecutionStatus = null, - TokensUsed = 0, - ExecutionStartedAt = DateTime.UtcNow - } - }; - }); + var t = node.Content as MeshThread ?? new MeshThread(); + return node with { Content = t with { IsExecuting = false, ActiveMessageId = null, ExecutionStartedAt = null } }; + }); + hub.Post(new SubmitMessageResponse { Success = false, Error = error }, + o => o.ResponseFor(delivery)); + } - // 3) Start execution on hosted hub — forward user's AccessContext - var executionHub = hub.GetHostedHub( - new Address($"{hub.Address}/_Exec"), - config => config.WithHandler(ExecuteMessageAsync), - HostedHubCreation.Always); + if (clientProvidedCells) + { + // GUI flow — cells already exist, respond and start immediately. + RespondAndStartExecution(); + } + else + { + // Server flow — create cells first, then respond and start execution. + // Response cell creation gates execution; user cell is fire-and-forget. + var meshService = hub.ServiceProvider.GetRequiredService(); - executionHub!.Post(request with { ResponsePath = responsePath }, - o => delivery.AccessContext != null ? o.WithAccessContext(delivery.AccessContext) : o); + meshService.CreateNode(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = mainEntity, + Content = new ThreadMessage + { + Role = "user", Text = request.UserMessageText, Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.ExecutedInput, CreatedBy = delivery.AccessContext?.ObjectId + } + }).Subscribe( + _ => logger?.LogDebug("[ThreadExec] User cell created: {Path}", $"{threadPath}/{userMsgId}"), + ex => logger?.LogDebug("[ThreadExec] User cell creation error (may already exist): {Error}", ex.Message)); - // 4) Response — nodes created successfully - hub.Post(new SubmitMessageResponse { Success = true }, o => o.ResponseFor(delivery)); - }, - error => + meshService.CreateNode(new MeshNode(responseMsgId, threadPath) { - var errorMsg = error.Message ?? "Node creation failed"; - logger?.LogError(error, "HandleSubmitMessage: node creation failed for {ThreadPath}: {Error}", - threadPath, errorMsg); - hub.Post(new SubmitMessageResponse { Success = false, Error = errorMsg }, - o => o.ResponseFor(delivery)); - }); + NodeType = ThreadMessageNodeType.NodeType, MainNode = mainEntity, + Content = new ThreadMessage + { + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse, + AgentName = request.AgentName, ModelName = request.ModelName + } + }).Subscribe( + _ => RespondAndStartExecution(), + ex => RespondWithError($"Failed to create response cell: {ex.Message}")); + } + return delivery.Processed(); } @@ -231,24 +414,26 @@ internal static IMessageDelivery ExecuteMessageAsync( var workspace = parentHub.ServiceProvider.GetRequiredService(); // Helper: push content to response message hub. - // Posts UpdateThreadMessageContent which is handled ON the grain — + // Posts UpdateThreadMessageContent which is handled ON the response grain — // calls workspace.UpdateMeshNode() locally → sync stream → clients. void PushToResponseMessage(string text, ImmutableList toolCalls, - string? agentName, string? modelName, string? delegationPath = null) + ImmutableList updatedNodes, + string? agentName, string? modelName) { - logger.LogInformation("[ThreadExec] PUSH_TO_MSG: responsePath={ResponsePath}, textLen={TextLen}, toolCalls={ToolCalls}", - responsePath, text.Length, toolCalls.Count); + logger.LogInformation("[ThreadExec] PUSH_TO_MSG: responsePath={ResponsePath}, textLen={TextLen}, toolCalls={ToolCalls}, updatedNodes={UpdatedNodes}", + responsePath, text.Length, toolCalls.Count, updatedNodes.Count); parentHub.Post(new UpdateThreadMessageContent { Text = text, ToolCalls = toolCalls, + UpdatedNodes = updatedNodes, AgentName = agentName, - ModelName = modelName, - DelegationPath = delegationPath + ModelName = modelName }, o => o.WithTarget(new Address(responsePath))); } - // Helper: update Thread execution state + // Helper: update Thread execution state via parentHub workspace. + // parentHub.GetWorkspace().UpdateMeshNode() is a synchronous function — no message needed. var threadWorkspace = parentHub.GetWorkspace(); void UpdateThreadExecution(Func mutate) { @@ -264,9 +449,13 @@ void UpdateThreadExecution(Func mutate) if (delivery.AccessContext != null) accessService?.SetContext(delivery.AccessContext); - // Initialize agent — returns IObservable - var chatClient = new AgentChatClient(parentHub.ServiceProvider); - chatClient.SetThreadId(threadPath); + // Reuse cached agent (skips 3+ seconds of agent initialization on 2nd+ message) + var chatClient = AgentCache.GetOrAdd(threadPath, _ => + { + var c = new AgentChatClient(parentHub.ServiceProvider); + c.SetThreadId(threadPath); + return c; + }); // Subscribe to Initialize: when agents are ready, start the streaming loop var initSub = chatClient.Initialize(request.ContextPath, request.ModelName) @@ -293,10 +482,6 @@ void UpdateThreadExecution(Func mutate) if (request.Attachments is { Count: > 0 }) client.SetAttachments(request.Attachments); - // Load history from workspace stream - LoadHistoryFromStream(client, threadWorkspace, workspace, threadPath, responseMsgId, logger); - - // Set execution context var userAccessContext = delivery.AccessContext; client.SetExecutionContext(new ThreadExecutionContext { @@ -306,22 +491,130 @@ void UpdateThreadExecution(Func mutate) UserAccessContext = userAccessContext }); - var toolCallLog = ImmutableList.Empty; + // Load history via GetDataRequest to each message — fully reactive + PushToResponseMessage("Loading conversation history...", ImmutableList.Empty, + ImmutableList.Empty, request.AgentName, request.ModelName); + + // Load history: subscribe to Thread stream → get Messages → GetDataRequest each → CombineLatest + threadWorkspace.GetStream(new MeshNodeReference())! + .Select(node => (node.Value?.Content as MeshThread)?.Messages ?? ImmutableList.Empty) + .Where(msgs => msgs.Count > 0) + .Take(1) + .Subscribe(allMsgIds => + { + // History = all messages EXCEPT the last one (response cell). + // The current user cell IS included — its text comes from the cell itself. + var historyMsgIds = allMsgIds.Count > 1 + ? allMsgIds.Take(allMsgIds.Count - 1).ToImmutableList() + : ImmutableList.Empty; + logger.LogInformation("[ThreadExec] Loading {Count} history messages via GetDataRequest for {ThreadPath}", + historyMsgIds.Count, threadPath); + + // Post GetDataRequest to each message, collect responses + var historySubjects = historyMsgIds.Select(msgId => + { + var subject = new System.Reactive.Subjects.AsyncSubject<(string Id, ThreadMessage? Msg)>(); + logger.LogDebug("[ThreadExec] HISTORY_REQ: posting GetDataRequest for {MsgPath}", + $"{threadPath}/{msgId}"); + var del = parentHub.Post(new GetDataRequest(new MeshNodeReference()), + o => o.WithTarget(new Address($"{threadPath}/{msgId}"))); + if (del != null) + { + logger.LogDebug("[ThreadExec] HISTORY_REQ: posted, delivery={Id} for {MsgId}", del.Id, msgId); + parentHub.RegisterCallback((IMessageDelivery)del, resp => + { + ThreadMessage? tmsg = null; + if (resp is IMessageDelivery gdr) + tmsg = (gdr.Message.Data as MeshNode)?.Content as ThreadMessage; + logger.LogDebug("[ThreadExec] HISTORY_RESP: {MsgId} → role={Role}, textLen={Len}, respType={Type}", + msgId, tmsg?.Role ?? "(null)", tmsg?.Text?.Length ?? -1, resp.Message?.GetType().Name); + subject.OnNext((msgId, tmsg)); + subject.OnCompleted(); + return resp; + }); + } + else + { + logger.LogDebug("[ThreadExec] HISTORY_REQ: Post returned null for {MsgId}", msgId); + subject.OnNext((msgId, null)); + subject.OnCompleted(); + } + return subject.AsObservable(); + }).ToList(); + + // When all responses arrive (or timeout), build history and start streaming + var historyObs = historySubjects.Count > 0 + ? Observable.CombineLatest(historySubjects).Take(1) + .Select(results => + { + var lookup = results.Where(r => r.Msg != null).ToDictionary(r => r.Id, r => r.Msg!); + return historyMsgIds + .Where(id => lookup.ContainsKey(id)) + .Select(id => + { + var msg = lookup[id]; + var role = msg.Role == "user" ? ChatRole.User : ChatRole.Assistant; + var text = msg.Text ?? ""; + + // For assistant messages: prepend tool call summaries so the + // agent knows what it did (tools called, data read, results) + if (role == ChatRole.Assistant && msg.ToolCalls is { Count: > 0 }) + { + var toolSummary = string.Join("\n", msg.ToolCalls.Select(tc => + $"[Tool: {tc.Name}({tc.Arguments ?? ""})" + + (tc.Result != null ? $" → {tc.Result[..Math.Min(500, tc.Result.Length)]}" : "") + + "]")); + text = $"{toolSummary}\n\n{text}"; + } + + return new ChatMessage(role, text); + }) + .ToImmutableList(); + }) + .Timeout(TimeSpan.FromSeconds(10)) + .Catch, Exception>(ex => + { + logger.LogDebug("[ThreadExec] HISTORY_TIMEOUT: {ThreadPath}, {Count} messages requested, error={Error}", + threadPath, historyMsgIds.Count, ex.Message); + return Observable.Return(ImmutableList.Empty); + }) + : Observable.Return(ImmutableList.Empty); + + historyObs.Take(1).Subscribe(chatHistory => + { + logger.LogInformation("[ThreadExec] Assembled {Count}/{Total} history messages for {ThreadPath}", + chatHistory.Count, historyMsgIds.Count, threadPath); + + var toolCallLog = ImmutableList.Empty; + var nodeChangeLog = ImmutableList.Empty; + // responseText is captured after InvokeAsync creates it (see below) + StringBuilder? capturedResponseText = null; + client.ForwardNodeChange = entry => { nodeChangeLog = nodeChangeLog.Add(entry); }; string? currentStatus = null; client.UpdateDelegationStatus = status => { currentStatus = status; + logger.LogInformation("[ThreadExec] DELEGATION_STATUS: threadPath={ThreadPath}, status={Status}, delegationPaths=[{Paths}]", + threadPath, status, string.Join(",", chatClient.DelegationPaths.Select(kv => $"{kv.Key}={kv.Value}"))); // Push immediately when delegation path becomes available — // the streaming loop is blocked during tool execution so the // throttle block never runs. This ensures the parent message // shows the delegation link while the sub-thread executes. - if (!string.IsNullOrEmpty(chatClient.LastDelegationPath)) + if (chatClient.DelegationPaths.TryGetValue(status, out var delPath)) { + // Stamp the path on the first unmatched delegation tool call + var stamped = false; toolCallLog = toolCallLog.Select(e => - e.Name.StartsWith("delegate_to") && e.DelegationPath == null - ? e with { DelegationPath = chatClient.LastDelegationPath } - : e).ToImmutableList(); - PushToResponseMessage("", toolCallLog, + { + if (!stamped && e.Name.StartsWith("delegate_to") && e.DelegationPath == null) + { + stamped = true; + return e with { DelegationPath = delPath }; + } + return e; + }).ToImmutableList(); + // Preserve any previously streamed text + PushToResponseMessage(capturedResponseText?.ToString() ?? "", toolCallLog, nodeChangeLog, request.AgentName, request.ModelName); } }; @@ -329,25 +622,52 @@ void UpdateThreadExecution(Func mutate) var agentDisplayName = request.AgentName ?? "Agent"; - // Run AI streaming via InvokeAsync — external I/O, not Orleans - var chatMessage = new ChatMessage(ChatRole.User, request.UserMessageText); - logger.LogInformation("[ThreadExec] Sending to agent: threadPath={ThreadPath}, agent={Agent}, model={Model}, msgLength={Length}", - threadPath, request.AgentName ?? "(default)", request.ModelName ?? "(default)", request.UserMessageText?.Length ?? 0); - string? firstDelegationPath = null; + // Build full message list: history (from GetDataRequest) + current message + // chatHistory already includes the current user message (loaded from the cell). + // Only add it if history is empty (delegation sub-thread, text from PendingUserMessage). + var allMessages = chatHistory.Count > 0 + ? chatHistory + : chatHistory.Add(new ChatMessage(ChatRole.User, request.UserMessageText)); + logger.LogInformation("[ThreadExec] Sending {Count} messages to agent ({HistoryCount} history + 1 new): threadPath={ThreadPath}, agent={Agent}", + allMessages.Count, chatHistory.Count, threadPath, request.AgentName ?? "(default)"); - logger.LogInformation("[ThreadExec] INVOKE_ASYNC_START: threadPath={ThreadPath}, responsePath={ResponsePath}", + logger.LogInformation("[ThreadExec] STREAMING_START: threadPath={ThreadPath}, responsePath={ResponsePath}", threadPath, responsePath); - hub.InvokeAsync(async ct => + // Run streaming on thread pool via Task.Run — the grain scheduler + // stays FREE to process tool call responses, delegation callbacks, and + // workspace updates. Without this, tool calls deadlock: they await a + // response that needs the grain scheduler which is blocked by InvokeAsync. + // + // DelayDeactivation keeps the grain alive while the thread pool task runs. + // BeginAsyncOperation signals the grain keep-alive timer. + // After await Task.Run(...), execution returns to the grain scheduler. + var executionCts = new CancellationTokenSource(); + ExecutionCancellations[threadPath] = executionCts; + // Cancel Task.Run when the hub disposes (grain deactivation). + // Without this, OnDeactivateAsync waits up to 120s for the Task.Run + // that's stuck on an AI API call with no cancellation signal. + hub.RegisterForDisposal(_ => executionCts.Cancel()); + // Push progress: generating + PushToResponseMessage("Generating response...", ImmutableList.Empty, + ImmutableList.Empty, request.AgentName, request.ModelName); + + _ = Task.Run(async () => { + var ct = executionCts.Token; var responseText = new StringBuilder(); + capturedResponseText = responseText; try { - logger.LogInformation("[ThreadExec] STREAMING_LOOP_ENTRY: {Time:HH:mm:ss.fff} threadPath={ThreadPath}", DateTime.UtcNow, threadPath); + logger.LogInformation("[ThreadExec] STREAMING_LOOP_ENTRY: {Time:HH:mm:ss.fff} threadPath={ThreadPath} (on thread pool)", DateTime.UtcNow, threadPath); + // Keep the grain alive during the entire execution — including tool calls + // and delegations where the streaming loop is blocked. + using var heartbeatSubscription = parentHub.BeginAsyncOperation(); var lastUpdate = DateTimeOffset.MinValue; var pendingCalls = ImmutableDictionary.Empty; string? lastCallKey = null; - await foreach (var update in client.GetStreamingResponseAsync([chatMessage], ct)) + // Pass ALL messages through the official AgentChatClient path + await foreach (var update in client.GetStreamingResponseAsync(allMessages, ct)) { // Capture function call / delegation activity for execution status foreach (var content in update.Contents) @@ -364,17 +684,22 @@ void UpdateThreadExecution(Func mutate) : formatted; var callKey = functionCall.CallId ?? $"{functionCall.Name}_{pendingCalls.Count}"; + var isDuplicate = pendingCalls.ContainsKey(callKey); pendingCalls = pendingCalls.SetItem(callKey, functionCall); lastCallKey = callKey; // Add pending tool call to local log — will be pushed on next throttled update - toolCallLog = toolCallLog.Add(new ToolCallEntry + // Skip if we already have an entry for this callKey (re-emitted content) + if (!isDuplicate) { - Name = functionCall.Name, - DisplayName = formatted, - Arguments = argsDetail, - Timestamp = DateTime.UtcNow - }); + toolCallLog = toolCallLog.Add(new ToolCallEntry + { + Name = functionCall.Name, + DisplayName = formatted, + Arguments = argsDetail, + Timestamp = DateTime.UtcNow + }); + } } else if (content is FunctionResultContent functionResult) { @@ -392,25 +717,31 @@ void UpdateThreadExecution(Func mutate) if (originalCall != null) { string? delegationPath = null; + string? resultText = null; + bool isSuccess; + + // Extract typed result fields when available (DelegationResult, etc.) + var (extractedText, extractedPath, extractedSuccess) = ExtractToolResult(functionResult.Result); + resultText = extractedText; + isSuccess = extractedSuccess; + if (originalCall.Name.StartsWith("delegate_to")) - { - delegationPath = chatClient.LastDelegationPath; - chatClient.LastDelegationPath = null; - firstDelegationPath ??= delegationPath; - } + delegationPath = extractedPath; - // Replace pending entry with final (has Result + DelegationPath) + // Replace pending entry with final (has Result + DelegationPath). + // Preserve DelegationPath if already stamped by UpdateDelegationStatus. + var idx = toolCallLog.FindIndex(e => e.Name == originalCall.Name && e.Result == null); + var existingDelegationPath = idx >= 0 ? toolCallLog[idx].DelegationPath : null; var finalEntry = new ToolCallEntry { Name = originalCall.Name, DisplayName = ToolStatusFormatter.Format(originalCall), Arguments = SerializeArgs(originalCall.Arguments), - Result = Truncate(functionResult.Result?.ToString()), - IsSuccess = functionResult.Result?.ToString()?.StartsWith("Error") != true, - DelegationPath = delegationPath, + Result = Truncate(resultText), + IsSuccess = isSuccess, + DelegationPath = delegationPath ?? existingDelegationPath, Timestamp = DateTime.UtcNow }; - var idx = toolCallLog.FindIndex(e => e.Name == originalCall.Name && e.Result == null); toolCallLog = idx >= 0 ? toolCallLog.SetItem(idx, finalEntry) : toolCallLog.Add(finalEntry); logger.LogDebug("[ThreadExec] TOOL_DONE: {Time:HH:mm:ss.fff} {Name} callId={CallId} delegation={Delegation} resultLen={ResultLen}", DateTime.UtcNow, originalCall.Name, originalCall.CallId, delegationPath, @@ -423,67 +754,78 @@ void UpdateThreadExecution(Func mutate) if (!string.IsNullOrEmpty(update.Text)) responseText.Append(update.Text); - // Push streaming content at ~1/sec via responseStream.Update - if (DateTimeOffset.UtcNow - lastUpdate > TimeSpan.FromMilliseconds(1000)) + // Push streaming content at ~1/3sec — reduced frequency to avoid + // overloading the grain scheduler (messages expire if queue backs up). + if (DateTimeOffset.UtcNow - lastUpdate > TimeSpan.FromMilliseconds(3000)) { - if (!string.IsNullOrEmpty(chatClient.LastDelegationPath)) + // Stamp delegation paths on any unmatched delegation tool calls + var pathValues = chatClient.DelegationPaths.Values.ToList(); + var pathIdx = 0; + toolCallLog = toolCallLog.Select(e => { - toolCallLog = toolCallLog.Select(e => - e.Name.StartsWith("delegate_to") && e.DelegationPath == null - ? e with { DelegationPath = chatClient.LastDelegationPath } - : e).ToImmutableList(); - } + if (e.Name.StartsWith("delegate_to") && e.DelegationPath == null && pathIdx < pathValues.Count) + return e with { DelegationPath = pathValues[pathIdx++] }; + return e; + }).ToImmutableList(); - PushToResponseMessage(responseText.ToString(), toolCallLog, + PushToResponseMessage(responseText.ToString(), toolCallLog, nodeChangeLog, request.AgentName, request.ModelName); lastUpdate = DateTimeOffset.UtcNow; } } - // Final update + // Final update — aggregate node changes (merges sub-thread changes with min/max versions) + var aggregatedChanges = AggregateNodeChanges(nodeChangeLog); logger.LogInformation("[ThreadExec] EXECUTION_COMPLETE: {Time:HH:mm:ss.fff} threadPath={ThreadPath}, responseLength={Length}, toolCalls={ToolCalls}", DateTime.UtcNow, threadPath, responseText.Length, toolCallLog.Count); var finalText = responseText.ToString(); - PushToResponseMessage(finalText, toolCallLog, - request.AgentName, request.ModelName, firstDelegationPath); - // Clear streaming state from Thread + PushToResponseMessage(finalText, toolCallLog, aggregatedChanges, + request.AgentName, request.ModelName); + // Clear streaming state UpdateThreadExecution(t => t with { IsExecuting = false, ExecutionStatus = null, ActiveMessageId = null, - ExecutionStartedAt = null, StreamingText = null, StreamingToolCalls = null + ExecutionStartedAt = null, StreamingText = null, StreamingToolCalls = null, + PendingUserMessage = null, PendingAgentName = null, PendingModelName = null, + PendingContextPath = null, PendingAttachments = null }); - // Notify parent thread that delegation completed - NotifyParentCompletion(parentHub, threadPath, finalText, true); + // Notify parent via SubmitMessageResponse so delegation callback resolves. + // Must post on the _Exec hub (hub) — the SubmitMessageResponse handler + // is registered there and forwards to the thread hub via ResponseFor. + NotifyParentCompletion(parentHub, threadPath, finalText, true, aggregatedChanges); } catch (OperationCanceledException) { logger.LogInformation("[ThreadExec] CANCELLED: {Time:HH:mm:ss.fff} threadPath={ThreadPath}", DateTime.UtcNow, threadPath); var cancelText = (responseText.ToString() + "\n\n*Cancelled*").Trim(); - PushToResponseMessage(cancelText, toolCallLog, request.AgentName, request.ModelName, firstDelegationPath); + PushToResponseMessage(cancelText, toolCallLog, nodeChangeLog, request.AgentName, request.ModelName); UpdateThreadExecution(t => t with { IsExecuting = false, ExecutionStatus = null, ActiveMessageId = null, ExecutionStartedAt = null, StreamingText = null, StreamingToolCalls = null }); - NotifyParentCompletion(parentHub, threadPath, cancelText, false); + NotifyParentCompletion(parentHub, threadPath, cancelText, false, nodeChangeLog); } catch (Exception ex) { logger.LogError(ex, "[ThreadExec] ERROR: {Time:HH:mm:ss.fff} threadPath={ThreadPath}", DateTime.UtcNow, threadPath); var errorText = (responseText.ToString() + $"\n\n*Error: {ex.Message}*").Trim(); - PushToResponseMessage(errorText, toolCallLog, request.AgentName, request.ModelName, firstDelegationPath); + PushToResponseMessage(errorText, toolCallLog, nodeChangeLog, request.AgentName, request.ModelName); UpdateThreadExecution(t => t with { IsExecuting = false, ExecutionStatus = null, ActiveMessageId = null, ExecutionStartedAt = null, StreamingText = null, StreamingToolCalls = null }); - NotifyParentCompletion(parentHub, threadPath, errorText, false); + NotifyParentCompletion(parentHub, threadPath, errorText, false, nodeChangeLog); + } + finally + { + ExecutionCancellations.TryRemove(threadPath, out _); + executionCts.Dispose(); } - }, ex => - { - logger.LogError(ex, "[ThreadExec] InvokeAsync error: {ThreadPath}", threadPath); - return Task.CompletedTask; }); + }); // end of historyObs.Subscribe + }); // end of threadStream.Subscribe (Messages) }, // end of Initialize().Subscribe onNext ex => logger.LogError(ex, "[ThreadExec] Initialize failed for {ThreadPath}", threadPath)); @@ -493,41 +835,7 @@ void UpdateThreadExecution(Func mutate) return delivery.Processed(); } - private static void LoadHistoryFromStream( - AgentChatClient client, IWorkspace threadWorkspace, IWorkspace workspace, - string threadPath, string responseMsgId, ILogger logger) - { - try - { - var threadStream = threadWorkspace.GetStream(new MeshNodeReference()); - var threadNode = threadStream?.Current?.Value; - var threadContent = threadNode?.Content as AI.Thread; - if (threadContent?.Messages.Count > 0) - { - var history = ImmutableList.Empty; - foreach (var msgId in threadContent.Messages) - { - if (msgId == responseMsgId) continue; - var msgStream = workspace.GetRemoteStream( - new Address($"{threadPath}/{msgId}"), new MeshNodeReference()); - var msgNode = msgStream.Current?.Value; - if (msgNode?.Content is ThreadMessage tmsg && tmsg.Type != ThreadMessageType.EditingPrompt) - history = history.Add(tmsg); - } - if (history.Count > 0) - { - client.SetConversationHistory(history); - logger.LogInformation("[ThreadExec] Loaded {Count} history messages for {ThreadPath}", - history.Count, threadPath); - } - } - } - catch (Exception ex) - { - logger.LogWarning(ex, "Failed to load conversation history for {ThreadPath}", threadPath); - } - } - + /// /// /// Push streaming content via DataChangeRequest to the response message hub. /// One-way message — the response hub updates its own local workspace. @@ -538,19 +846,54 @@ private static void LoadHistoryFromStream( /// The parent's delegation tool handler resolves its TaskCompletionSource. /// Only posts if this thread IS a child (path has a parent response message segment). /// - private static void NotifyParentCompletion(IMessageHub hub, string threadPath, string responseText, bool success) + private static void NotifyParentCompletion( + IMessageHub hub, string threadPath, string responseText, bool success, + ImmutableList? updatedNodes = null) { var logger = hub.ServiceProvider.GetRequiredService>(); - logger.LogInformation("[ThreadExec] NOTIFY_PARENT: threadPath={ThreadPath}, success={Success}, textLen={TextLen}", - threadPath, success, responseText.Length); - var completed = DelegationTracker.TryComplete(new DelegationCompletedEvent + var status = success ? SubmitMessageStatus.ExecutionCompleted + : SubmitMessageStatus.ExecutionFailed; + logger.LogInformation("[ThreadExec] NOTIFY_PARENT: threadPath={ThreadPath}, status={Status}, textLen={TextLen}", + threadPath, status, responseText.Length); + + // Invoke the completion callback registered by HandleSubmitMessage. + // This posts a SubmitMessageResponse(ExecutionCompleted) via ResponseFor(originalDelivery) + // on the thread hub, which routes back to the client's RegisterCallback. + if (CompletionCallbacks.TryGetValue(threadPath, out var callback)) { - ThreadPath = threadPath, - ResponseText = Truncate(responseText, 500), - Success = success - }); - logger.LogInformation("[ThreadExec] NOTIFY_PARENT_RESULT: threadPath={ThreadPath}, resolved={Resolved}", - threadPath, completed); + callback(new SubmitMessageResponse + { + Success = success, + Status = status, + ResponseText = Truncate(responseText, 500), + UpdatedNodes = updatedNodes + }); + } + else + { + logger.LogWarning("[ThreadExec] No completion callback for {ThreadPath}", threadPath); + } + } + + /// + /// Aggregates node change entries: for the same path, takes min(VersionBefore) and max(VersionAfter). + /// This merges changes from the current thread and any delegation sub-threads. + /// + internal static ImmutableList AggregateNodeChanges(ImmutableList entries) + { + if (entries.Count <= 1) return entries; + return entries + .GroupBy(e => e.Path) + .Select(g => g.Aggregate((a, b) => a with + { + VersionBefore = Min(a.VersionBefore, b.VersionBefore), + VersionAfter = Max(a.VersionAfter, b.VersionAfter), + Operation = b.Operation // Last operation wins (e.g., Created then Updated → Updated) + })) + .ToImmutableList(); + + static long? Min(long? a, long? b) => a == null ? b : b == null ? a : Math.Min(a.Value, b.Value); + static long? Max(long? a, long? b) => a == null ? b : b == null ? a : Math.Max(a.Value, b.Value); } private static string? SerializeArgs(IDictionary? args) @@ -591,76 +934,86 @@ private static void NotifyParentCompletion(IMessageHub hub, string threadPath, s return value[..(maxLength - 3)] + "..."; } + /// + /// Extracts result text, delegation path, and success from a tool result. + /// Handles DelegationResult objects directly (no ToString → JSON round-trip). + /// Falls back to JSON parsing for serialized results, then plain toString. + /// + private static (string? ResultText, string? DelegationPath, bool IsSuccess) ExtractToolResult(object? result) + { + if (result is null) + return (null, null, true); + + // Typed DelegationResult — direct property access, no parsing + if (result is DelegationResult dr) + return (dr.Result, dr.ThreadId, dr.Success); + + var text = result.ToString(); + if (string.IsNullOrEmpty(text)) + return (null, null, true); + + // Try JSON parsing only if text looks like JSON (starts with { or [) + var trimmed = text.AsSpan().TrimStart(); + if (trimmed.Length > 0 && (trimmed[0] == '{' || trimmed[0] == '[')) + try + { + using var doc = JsonDocument.Parse(text); + var root = doc.RootElement; + string? threadId = null; + if (root.TryGetProperty("threadId", out var tidProp) || + root.TryGetProperty("ThreadId", out tidProp)) + threadId = tidProp.GetString(); + + string? resultText = null; + if (root.TryGetProperty("result", out var resProp) || + root.TryGetProperty("Result", out resProp)) + resultText = resProp.GetString(); + + var success = true; + if (root.TryGetProperty("success", out var sucProp) || + root.TryGetProperty("Success", out sucProp)) + success = sucProp.GetBoolean(); + + return (resultText ?? text, threadId, success); + } + catch + { + // Not JSON — use raw text + } + + var isSuccess = !text.StartsWith("Error", StringComparison.Ordinal); + return (text, null, isSuccess); + } + private static IMessageDelivery HandleCancelStream( IMessageHub hub, IMessageDelivery delivery) { var logger = hub.ServiceProvider.GetService>(); var threadPath = hub.Address.Path; - // Bottom-up cancellation: cancel sub-threads first (via request/response), then own execution. - var meshService = hub.ServiceProvider.GetService(); - if (meshService != null) + // Read Thread.StreamingToolCalls from workspace (runs on grain scheduler — safe). + // Find active delegation sub-threads and propagate cancel via Post (fire-and-forget). + hub.GetWorkspace().UpdateMeshNode(node => { - hub.InvokeAsync(async ct => + var thread = node.Content as MeshThread; + if (thread?.StreamingToolCalls is { Count: > 0 }) { - try - { - // Find active sub-threads via Thread.ActiveMessageId → DelegationPath - var threadNode = await meshService.QueryAsync($"path:{threadPath}", ct: ct) - .FirstOrDefaultAsync(ct); - var thread = threadNode?.Content as MeshThread; - - if (thread is { IsExecuting: true, ActiveMessageId: { } activeMsgId }) - { - var activeMsgPath = $"{threadPath}/{activeMsgId}"; - var activeMsg = await meshService.QueryAsync($"path:{activeMsgPath}", ct: ct) - .FirstOrDefaultAsync(ct); - - if (activeMsg?.Content is ThreadMessage { DelegationPath: { Length: > 0 } delegationPath }) - { - logger?.LogInformation("[ThreadExec] Propagating cancel to sub-thread {SubThread}", delegationPath); - var cancelDelivery = hub.Post(new CancelThreadStreamRequest { ThreadPath = delegationPath }, - o => o.WithTarget(new Address(delegationPath))); - if (cancelDelivery != null) - { - try - { - await hub.RegisterCallback(cancelDelivery, (d, _) => Task.FromResult(d), ct) - .WaitAsync(TimeSpan.FromSeconds(10), ct); - } - catch (TimeoutException) - { - logger?.LogWarning("[ThreadExec] Sub-thread cancel timed out for {SubThread}", delegationPath); - } - } - } - } - } - catch (Exception ex) + foreach (var tc in thread.StreamingToolCalls.Where( + tc => !string.IsNullOrEmpty(tc.DelegationPath) && tc.Result == null)) { - logger?.LogWarning(ex, "[ThreadExec] Error propagating cancellation for {ThreadPath}", threadPath); + logger?.LogInformation("[ThreadExec] Propagating cancel to sub-thread {SubThread}", tc.DelegationPath); + hub.Post(new CancelThreadStreamRequest { ThreadPath = tc.DelegationPath! }, + o => o.WithTarget(new Address(tc.DelegationPath!))); } + } + return node; // No state change needed + }); - // Cancel own execution (after sub-threads confirmed) - var execHub = hub.GetHostedHub(new Address($"{hub.Address}/_Exec"), HostedHubCreation.Never); - if (execHub != null) - { - logger?.LogInformation("[ThreadExec] Cancelling own execution for {ThreadPath}", threadPath); - execHub.CancelCurrentExecution(); - } - }, ex => - { - logger?.LogWarning(ex, "[ThreadExec] Error during cancel for {ThreadPath}", threadPath); - var execHub = hub.GetHostedHub(new Address($"{hub.Address}/_Exec"), HostedHubCreation.Never); - execHub?.CancelCurrentExecution(); - return Task.CompletedTask; - }); - } - else + // Cancel own execution via CancellationTokenSource (streaming runs on thread pool) + if (ExecutionCancellations.TryGetValue(threadPath, out var cts)) { - // No mesh service — just cancel own execution - var execHub = hub.GetHostedHub(new Address($"{hub.Address}/_Exec"), HostedHubCreation.Never); - execHub?.CancelCurrentExecution(); + logger?.LogInformation("[ThreadExec] Cancelling own execution for {ThreadPath}", threadPath); + cts.Cancel(); } // Post response so parent can await confirmation diff --git a/src/MeshWeaver.AI/ThreadLayoutAreas.cs b/src/MeshWeaver.AI/ThreadLayoutAreas.cs index 974b350b7..6c870330f 100644 --- a/src/MeshWeaver.AI/ThreadLayoutAreas.cs +++ b/src/MeshWeaver.AI/ThreadLayoutAreas.cs @@ -33,15 +33,15 @@ public static class ThreadLayoutAreas /// public static MessageHubConfiguration AddThreadLayoutAreas(this MessageHubConfiguration configuration) => configuration - .WithHandler(HandleResubmitMessage) - .WithHandler(HandleDeleteFromMessage) - .WithHandler(HandleEditMessage) + .WithHandler(ThreadMessageHandlers.HandleResubmitMessage) + .WithHandler(ThreadMessageHandlers.HandleDeleteFromMessage) .AddDefaultMeshMenu() .AddNodeMenuItems("SidePanel", SidePanelMenuProvider) .AddNodeMenuItems(DelegationsMenuProvider) .AddLayout(layout => layout .WithDefaultArea(ThreadNodeType.ThreadArea) .WithView(ThreadNodeType.ThreadArea, ThreadView) + .WithView(MeshNodeLayoutAreas.OverviewArea, ThreadProgressView) .WithView(ThreadNodeType.ThreadChatArea, ThreadChatView) .WithView(ThreadNodeType.StreamingArea, StreamingView) .WithView(ThreadNodeType.HistoryArea, HistoryView) @@ -242,10 +242,45 @@ public static UiControl ThreadsCatalog(LayoutAreaHost host, RenderingContext _) } /// - /// Streaming area: shows the active response message cell and any delegation sub-threads. - /// Reactive — emits null when idle, a LayoutAreaControl for the streaming cell when executing. - /// Parent threads subscribe to child threads' Streaming area to see cascading progress. - /// Returns IObservable so it updates reactively as execution state changes. + /// Overview area for Thread nodes — overrides the default property editor. + /// Shows the active/last message as a LayoutAreaControl (bubble with tool calls). + /// If executing: shows the active message cell (streaming + tool calls). + /// If finished: shows the last response message cell. + /// Never shows the Thread record's properties as an editor. + /// + public static IObservable ThreadProgressView(LayoutAreaHost host, RenderingContext _) + { + var hubPath = host.Hub.Address.ToString(); + var stream = host.Workspace.GetStream(); + + return stream! + .Select(nodes => + { + var node = nodes!.FirstOrDefault(n => n.Path == hubPath); + var thread = node?.Content as MeshThread; + if (thread == null) return (UiControl?)null; + + // Find which message to show + string? messageId = null; + if (thread.IsExecuting && !string.IsNullOrEmpty(thread.ActiveMessageId)) + messageId = thread.ActiveMessageId; + else if (thread.Messages.Count > 0) + messageId = thread.Messages[^1]; // last message + + if (string.IsNullOrEmpty(messageId)) + return (UiControl?)Controls.Html( + "

No messages yet.

"); + + var messagePath = $"{hubPath}/{messageId}"; + return (UiControl?)new LayoutAreaControl(messagePath, + new LayoutAreaReference(ThreadMessageNodeType.OverviewArea)) + .WithSpinnerType(SpinnerType.Skeleton); + }); + } + + /// + /// Streaming area: if thread has an executing cell, returns its default layout area. + /// Otherwise null. Simple passthrough — no title, no wrapping. /// public static IObservable StreamingView(LayoutAreaHost host, RenderingContext _) { @@ -267,7 +302,7 @@ public static UiControl ThreadsCatalog(LayoutAreaHost host, RenderingContext _) var responsePath = $"{hubPath}/{state.ActiveMessageId}"; return (UiControl?)new LayoutAreaControl(responsePath, - new LayoutAreaReference("Streaming")); + new LayoutAreaReference(ThreadMessageNodeType.OverviewArea)); }); } @@ -460,181 +495,27 @@ private static string GetThreadTitle(MeshNode? node) => !string.IsNullOrEmpty(node?.Name) ? node.Name : "Thread"; /// - /// Handles DeleteFromMessageRequest — truncates Messages from the given message onwards. + /// Adds the Threads view to the layout — shows node-scoped thread history. /// - private static IMessageDelivery HandleDeleteFromMessage( - IMessageHub hub, - IMessageDelivery delivery) - { - var request = delivery.Message; - var logger = hub.ServiceProvider.GetRequiredService>(); - logger.LogInformation("HandleDeleteFromMessage: threadPath={ThreadPath}, messageId={MessageId}", - request.ThreadPath, request.MessageId); - - hub.InvokeAsync(() => - { - hub.ServiceProvider.GetRequiredService() - .GetStream()?.Take(1).Subscribe(nodes => - { - var threadNode = nodes?.FirstOrDefault(n => n.Path == request.ThreadPath); - var currentContent = threadNode?.Content as MeshThread ?? new MeshThread(); - - var msgList = currentContent.Messages.ToList(); - var msgIndex = msgList.IndexOf(request.MessageId); - if (msgIndex < 0) return; - - var updatedMsgList = msgList.Take(msgIndex).ToImmutableList(); - var newContent = currentContent with { Messages = updatedMsgList }; - var updatedNode = (threadNode ?? new MeshNode(request.ThreadPath)) with { Content = newContent }; - hub.Post(new DataChangeRequest { Updates = [updatedNode] }); - }); - }); - - return delivery.Processed(); - } + public static LayoutDefinition AddThreadsLayoutArea(this LayoutDefinition layout) + => layout.WithView("Threads", ThreadsView); /// - /// Handles ResubmitMessageRequest — keeps the user message, removes the response - /// (and anything after it), then creates only a new output cell and starts execution. + /// Adds the Threads view to the hub's layout configuration. /// - private static IMessageDelivery HandleResubmitMessage( - IMessageHub hub, - IMessageDelivery delivery) - { - var request = delivery.Message; - var logger = hub.ServiceProvider.GetRequiredService>(); - logger.LogInformation("HandleResubmitMessage: threadPath={ThreadPath}, messageId={MessageId}", - request.ThreadPath, request.MessageId); - - var workspace = hub.GetWorkspace(); - workspace.GetStream()?.Take(1).Subscribe(nodes => - { - var threadNode = nodes?.FirstOrDefault(n => n.Path == request.ThreadPath); - var currentContent = threadNode?.Content as MeshThread ?? new MeshThread(); - - var msgIndex = currentContent.Messages.IndexOf(request.MessageId); - if (msgIndex < 0) return; - - // Keep the user message (msgIndex), remove everything after it - var updatedMsgList = currentContent.Messages.Take(msgIndex + 1).ToImmutableList(); - - // Create new response cell only - var responseMsgId = Guid.NewGuid().ToString("N")[..8]; - var responsePath = $"{request.ThreadPath}/{responseMsgId}"; - var mainEntity = threadNode?.MainNode ?? request.ThreadPath; - var meshService = hub.ServiceProvider.GetRequiredService(); - - meshService.CreateNode(new MeshNode(responseMsgId, request.ThreadPath) - { - NodeType = ThreadMessageNodeType.NodeType, - MainNode = mainEntity, - Content = new ThreadMessage - { - Id = responseMsgId, - Role = "assistant", - Text = "", - Timestamp = DateTime.UtcNow, - Type = ThreadMessageType.AgentResponse - } - }).Subscribe(_ => - { - // Update thread: keep user msg, add new response, start execution - workspace.UpdateMeshNode(node => - { - var thread = node.Content as MeshThread ?? new MeshThread(); - return node with - { - Content = thread with - { - Messages = updatedMsgList.Add(responseMsgId), - IsExecuting = true, - ActiveMessageId = responseMsgId, - ExecutionStatus = null, - TokensUsed = 0, - ExecutionStartedAt = DateTime.UtcNow, - StreamingText = null, - StreamingToolCalls = null - } - }; - }); - - // Start execution on hosted hub - var executionHub = hub.GetHostedHub( - new Address($"{hub.Address}/_Exec"), - config => config.WithHandler(ThreadExecution.ExecuteMessageAsync), - HostedHubCreation.Always); - - executionHub!.Post(new SubmitMessageRequest - { - ThreadPath = request.ThreadPath, - UserMessageText = request.UserMessageText, - ResponsePath = responsePath, - ContextPath = mainEntity - }, o => delivery.AccessContext != null ? o.WithAccessContext(delivery.AccessContext) : o); - }, - ex => logger.LogError(ex, "HandleResubmitMessage: failed to create response cell for {ThreadPath}", request.ThreadPath)); - }); - - return delivery.Processed(); - } + public static MessageHubConfiguration AddThreadsLayoutArea(this MessageHubConfiguration configuration) + => configuration.AddLayout(layout => layout.AddThreadsLayoutArea()); /// - /// Handles EditMessageRequest — truncates Messages from the given message onwards, - /// creates a new EditingPrompt message node, and appends it to Messages. + /// Renders the Threads area showing node-scoped thread history. /// - private static IMessageDelivery HandleEditMessage( - IMessageHub hub, - IMessageDelivery delivery) + private static UiControl ThreadsView(LayoutAreaHost host, RenderingContext _) { - var request = delivery.Message; - var logger = hub.ServiceProvider.GetRequiredService>(); - logger.LogInformation("HandleEditMessage: threadPath={ThreadPath}, messageId={MessageId}", - request.ThreadPath, request.MessageId); - - var editMsgId = Guid.NewGuid().ToString("N")[..8]; - var meshService = hub.ServiceProvider.GetRequiredService(); - - // Create editing prompt node first - meshService.CreateNodeAsync(new MeshNode(editMsgId, request.ThreadPath) - { - NodeType = ThreadMessageNodeType.NodeType, - Content = new ThreadMessage - { - Id = editMsgId, - Role = "user", - Text = request.MessageText, - Timestamp = DateTime.UtcNow, - Type = ThreadMessageType.EditingPrompt - } - }).ContinueWith(t => - { - if (t.IsFaulted) - { - logger.LogError(t.Exception, "HandleEditMessage: node creation FAILED for {ThreadPath}", request.ThreadPath); - return; - } - - // Update Messages: truncate from the clicked message, append editing prompt - hub.InvokeAsync(() => - { - hub.ServiceProvider.GetRequiredService() - .GetStream()?.Take(1).Subscribe(nodes => - { - var threadNode = nodes?.FirstOrDefault(n => n.Path == request.ThreadPath); - var currentContent = threadNode?.Content as MeshThread ?? new MeshThread(); - - var msgList = currentContent.Messages.ToList(); - var msgIndex = msgList.IndexOf(request.MessageId); - if (msgIndex < 0) return; - - var updatedMsgList = msgList.Take(msgIndex).Concat([editMsgId]).ToImmutableList(); - var newContent = currentContent with { Messages = updatedMsgList }; - var updatedNode = (threadNode ?? new MeshNode(request.ThreadPath)) with { Content = newContent }; - hub.Post(new DataChangeRequest { Updates = [updatedNode] }); - }); - }); - }); - - return delivery.Processed(); + var nodePath = host.Hub.Address.ToString(); + return Controls.MeshSearch + .WithHiddenQuery($"nodeType:Thread namespace:{nodePath}/{ThreadNodeType.ThreadPartition}") + .WithNamespace(nodePath) + .WithRenderMode(MeshSearchRenderMode.Flat) + .WithCreateNodeType("Thread"); } } diff --git a/src/MeshWeaver.AI/ThreadMessageActionRequests.cs b/src/MeshWeaver.AI/ThreadMessageActionRequests.cs index ba8511c95..08e4e205e 100644 --- a/src/MeshWeaver.AI/ThreadMessageActionRequests.cs +++ b/src/MeshWeaver.AI/ThreadMessageActionRequests.cs @@ -1,36 +1,3 @@ -namespace MeshWeaver.AI; - -/// -/// Request to resubmit a user message in a thread. -/// The handler truncates ThreadMessages from the given message onwards, -/// then posts a new SubmitMessageRequest with the provided text. -/// -public record ResubmitMessageRequest -{ - public required string ThreadPath { get; init; } - public required string MessageId { get; init; } - public required string UserMessageText { get; init; } -} - -/// -/// Request to delete a message and all subsequent messages from a thread. -/// The handler truncates ThreadMessages from the given message onwards. -/// -public record DeleteFromMessageRequest -{ - public required string ThreadPath { get; init; } - public required string MessageId { get; init; } -} - -/// -/// Request to edit a user message in a thread. -/// The handler truncates ThreadMessages from the given message onwards, -/// creates a new EditingPrompt message node with the original text, -/// and appends it to ThreadMessages so the user can edit and resubmit. -/// -public record EditMessageRequest -{ - public required string ThreadPath { get; init; } - public required string MessageId { get; init; } - public required string MessageText { get; init; } -} +// Thread message action request types are defined in MeshWeaver.Layout.ThreadMessageActionRequests +// so they can be used from Blazor without referencing MeshWeaver.AI. +// This file is kept as a marker — the actual types are in MeshWeaver.Layout. diff --git a/src/MeshWeaver.AI/ThreadMessageHandlers.cs b/src/MeshWeaver.AI/ThreadMessageHandlers.cs new file mode 100644 index 000000000..92087df76 --- /dev/null +++ b/src/MeshWeaver.AI/ThreadMessageHandlers.cs @@ -0,0 +1,106 @@ +using System.Collections.Immutable; +using MeshWeaver.Data; +using MeshWeaver.Graph; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.AI; + +/// +/// Handlers for thread message operations: resubmit (re-evaluate) and delete. +/// Factored out from ThreadLayoutAreas for clarity. +/// All handlers are synchronous (no await) and use workspace.UpdateMeshNode +/// in the handler body (grain scheduler) or hub.Post (safe from any thread). +/// +public static class ThreadMessageHandlers +{ + /// + /// Handles DeleteFromMessageRequest — truncates Messages from the given message onwards. + /// + internal static IMessageDelivery HandleDeleteFromMessage( + IMessageHub hub, + IMessageDelivery delivery) + { + var request = delivery.Message; + hub.GetWorkspace().UpdateMeshNode(node => + { + var thread = node.Content as MeshThread ?? new MeshThread(); + var msgIndex = thread.Messages.IndexOf(request.MessageId); + if (msgIndex < 0) return node; + return node with + { + Content = thread with { Messages = thread.Messages.Take(msgIndex).ToImmutableList() } + }; + }); + return delivery.Processed(); + } + + /// + /// Handles ResubmitMessageRequest — keeps the user message, deletes old response nodes, + /// creates a new response cell, then starts execution. + /// + internal static IMessageDelivery HandleResubmitMessage( + IMessageHub hub, + IMessageDelivery delivery) + { + var request = delivery.Message; + var logger = hub.ServiceProvider.GetRequiredService>(); + + var responseMsgId = request.OutputMessageId ?? Guid.NewGuid().ToString("N")[..8]; + var responsePath = $"{request.ThreadPath}/{responseMsgId}"; + + // Update Thread: truncate Messages + append new output ID, set executing. + string? contextPath = null; + hub.GetWorkspace().UpdateMeshNode(node => + { + contextPath = node.MainNode != node.Path ? node.MainNode : null; + var thread = node.Content as MeshThread ?? new MeshThread(); + var msgIndex = thread.Messages.IndexOf(request.MessageId); + if (msgIndex < 0) return node; + + return node with + { + Content = thread with + { + Messages = thread.Messages.Take(msgIndex + 1).ToImmutableList().Add(responseMsgId), + IsExecuting = true, + ActiveMessageId = responseMsgId, + ExecutionStatus = null, + TokensUsed = 0, + ExecutionStartedAt = DateTime.UtcNow, + StreamingText = null, + StreamingToolCalls = null + } + }; + }); + + // Output cell is created by the click handler (same as GUI creates cells for submit) + + // Push progress to output cell + hub.Post(new UpdateThreadMessageContent { Text = "Allocating agent..." }, + o => o.WithTarget(new Address(responsePath))); + + // Start execution directly — no waiting for cell creation + var executionHub = hub.GetHostedHub( + new Address($"{hub.Address}/_Exec"), + config => config.WithHandler(ThreadExecution.ExecuteMessageAsync), + HostedHubCreation.Always); + + executionHub!.Post(new SubmitMessageRequest + { + ThreadPath = request.ThreadPath, + UserMessageText = request.UserMessageText, + UserMessageId = request.MessageId, + ResponseMessageId = responseMsgId, + ResponsePath = responsePath, + ContextPath = contextPath + }, o => delivery.AccessContext != null ? o.WithAccessContext(delivery.AccessContext) : o); + + return delivery.Processed(); + } +} diff --git a/src/MeshWeaver.AI/ThreadMessageLayoutAreas.cs b/src/MeshWeaver.AI/ThreadMessageLayoutAreas.cs index ce618ca4e..1e07c28ca 100644 --- a/src/MeshWeaver.AI/ThreadMessageLayoutAreas.cs +++ b/src/MeshWeaver.AI/ThreadMessageLayoutAreas.cs @@ -31,6 +31,7 @@ public static MessageHubConfiguration AddThreadMessageViews(this MessageHubConfi .AddLayout(layout => layout .WithDefaultArea(ThreadMessageNodeType.OverviewArea) .WithView(ThreadMessageNodeType.OverviewArea, Overview) + .WithView("Edit", EditArea) .WithView("Streaming", StreamingCompact) .WithView(MeshNodeLayoutAreas.SettingsArea, SettingsLayoutArea.Settings) .WithView(MeshNodeLayoutAreas.MetadataArea, MeshNodeLayoutAreas.Metadata) @@ -84,27 +85,19 @@ public static MessageHubConfiguration AddThreadMessageViews(this MessageHubConfi stack = stack.WithView(Controls.Html($"
{chips}
")); } - // Row 3: Delegation sub-threads (recursive — embed their StreamingArea) - foreach (var tc in msg.ToolCalls.Where(tc => !string.IsNullOrEmpty(tc.DelegationPath))) + // Row 3: Delegation sub-threads as simple chips (no nesting — prevents visual noise) + var delegationCalls = msg.ToolCalls.Where(tc => !string.IsNullOrEmpty(tc.DelegationPath)).ToList(); + if (delegationCalls.Count > 0) { - var icon = tc.Result != null ? "✓" : "✹"; - var name = (tc.DisplayName ?? tc.Name); - if (name.Length > 30) name = name[..27] + "..."; - - var delStack = Controls.Stack - .WithStyle("border-left:2px solid var(--accent-fill-rest); padding-left:6px; margin-top:2px;"); - - delStack = delStack.WithView(Controls.Html( - $"{icon} {System.Web.HttpUtility.HtmlEncode(name)}")); - - if (tc.Result == null) + var delChips = string.Join(" ", delegationCalls.Select(tc => { - // Recurse: embed sub-thread's StreamingArea - delStack = delStack.WithView( - new LayoutAreaControl(tc.DelegationPath!, new LayoutAreaReference(ThreadNodeType.StreamingArea))); - } - - stack = stack.WithView(delStack); + var name = (tc.DisplayName ?? tc.Name); + if (name.Length > 25) name = name[..22] + "..."; + var icon = tc.Result != null ? "✓" : "●"; + var color = tc.Result != null ? "var(--neutral-foreground-hint)" : "var(--accent-fill-rest)"; + return $"{icon} {System.Web.HttpUtility.HtmlEncode(name)}"; + })); + stack = stack.WithView(Controls.Html($"
{delChips}
")); } return (UiControl?)stack; @@ -125,16 +118,16 @@ private static IMessageDelivery HandleUpdateContent( hub.Address, msg.Text?.Length ?? -1, msg.ToolCalls?.Count ?? -1); hub.GetWorkspace().UpdateMeshNode(node => { - var current = node.Content as ThreadMessage ?? new ThreadMessage { Id = node.Id, Role = "assistant", Text = "" }; + var current = node.Content as ThreadMessage ?? new ThreadMessage { Role = "assistant", Text = "" }; return node with { Content = current with { Text = msg.Text ?? current.Text, ToolCalls = msg.ToolCalls ?? current.ToolCalls, + UpdatedNodes = msg.UpdatedNodes ?? current.UpdatedNodes, AgentName = msg.AgentName ?? current.AgentName, - ModelName = msg.ModelName ?? current.ModelName, - DelegationPath = msg.DelegationPath ?? current.DelegationPath + ModelName = msg.ModelName ?? current.ModelName } }; }); @@ -145,6 +138,8 @@ private static IMessageDelivery HandleUpdateContent( /// Renders the Overview area for a ThreadMessage node. /// Emits control once from first node emission. Text and tool calls are data-bound /// via JsonPointerReference — updates flow through host.UpdateData, no control rebuilds. + /// Editing is handled purely on the Blazor UI side (ThreadMessageBubbleView toggles + /// between readonly and Edit LayoutArea). ///
public static IObservable Overview(LayoutAreaHost host, RenderingContext _) { @@ -158,18 +153,45 @@ private static IMessageDelivery HandleUpdateContent( // and push to data section. The bubble binds to the view model via JsonPointerReference. var syncStream = host.Workspace.GetStream(new MeshNodeReference()); + var msgLogger = host.Hub.ServiceProvider.GetService() + ?.CreateLogger("MeshWeaver.AI.MsgLayout"); host.SubscribeToDataStream(MessageDataKey, syncStream! - .Select(change => change.Value?.Content as ThreadMessage) + .Select(change => + { + var msg = change.Value?.Content as ThreadMessage; + msgLogger?.LogInformation("[MsgLayout] STREAM_EMIT: hub={Hub}, hasContent={HasContent}, textLen={TextLen}", + host.Hub.Address, msg != null, msg?.Text?.Length ?? -1); + return msg; + }) .Where(m => m != null) .Select(m => (ThreadMessageViewModel.FromMessage(m!) with { Text = ConvertReferencesToLinks(m!.Text ?? "") })) .DistinctUntilChanged() - .Select(vm => (object)vm)); + .Select(vm => + { + msgLogger?.LogInformation("[MsgLayout] DATA_PUSH: hub={Hub}, textLen={TextLen}, toolCalls={ToolCalls}", + host.Hub.Address, ((ThreadMessageViewModel)vm).Text.Length, ((ThreadMessageViewModel)vm).ToolCalls.Count); + return (object)vm; + })); // Emit control once — role/author are static, text/toolCalls are data-bound. - return syncStream! + // Try current value first (synchronous) — the stream may have already replayed + // before this subscription started. Fall back to observable for lazy activation. + var currentMsg = syncStream!.Current?.Value?.Content as ThreadMessage; + if (currentMsg != null) + { + msgLogger?.LogInformation("[MsgLayout] CONTROL_EMIT_SYNC: hub={Hub}, role={Role}, textLen={TextLen}", + hubPath, currentMsg.Role, currentMsg.Text?.Length ?? 0); + var control = currentMsg.Type == ThreadMessageType.EditingPrompt + ? BuildEditingOverview(host, currentMsg, threadPath, messageId) + : BuildMessageOverview(host, currentMsg, threadPath, messageId); + return Observable.Return((UiControl?)control); + } + + msgLogger?.LogInformation("[MsgLayout] CONTROL_EMIT_ASYNC: hub={Hub}, waiting for first emission", hubPath); + return syncStream .Select(change => change.Value?.Content as ThreadMessage) .Where(m => m != null) .Take(1) @@ -182,6 +204,73 @@ private static IMessageDelivery HandleUpdateContent( }); } + /// + /// Renders the Edit area for a ThreadMessage node. + /// Shows a MarkdownEditorControl with the current text and a Submit button. + /// Submit posts ResubmitMessageRequest (re-executes with edited text). + /// Cancel/Done is handled by the Blazor bubble (local isEditing toggle). + /// + public static IObservable EditArea(LayoutAreaHost host, RenderingContext _) + { + var hubPath = host.Hub.Address.ToString(); + var lastSlash = hubPath.LastIndexOf('/'); + var threadPath = lastSlash > 0 ? hubPath[..lastSlash] : hubPath; + var messageId = lastSlash > 0 ? hubPath[(lastSlash + 1)..] : hubPath; + + var syncStream = host.Workspace.GetStream(new MeshNodeReference()); + + return syncStream! + .Select(change => change.Value?.Content as ThreadMessage) + .Where(m => m != null) + .Take(1) + .Select(msg => + { + const string textDataId = "editText"; + host.UpdateData(textDataId, msg!.Text ?? ""); + + var editor = new MarkdownEditorControl() + { Value = new JsonPointerReference(LayoutAreaReference.GetDataPointer(textDataId)) } + .WithDocumentId($"{threadPath}/{messageId}") + .WithHeight("120px") + .WithMaxHeight("200px") + .WithPlaceholder("Edit your message..."); + + var buttonRow = Controls.Stack + .WithOrientation(Orientation.Horizontal) + .WithStyle("gap: 8px; justify-content: flex-end; margin-top: 8px;") + .WithView(Controls.Button("Submit") + .WithAppearance(Appearance.Accent) + .WithIconStart(FluentIcons.Send(IconSize.Size16)) + .WithClickAction(actx => + { + actx.Host.Stream.GetDataStream(textDataId).Take(1).Subscribe(editedText => + { + var outId = Guid.NewGuid().ToString("N")[..8]; + actx.Hub.Post(new CreateNodeRequest(new MeshNode(outId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = threadPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath))); + actx.Hub.Post(new ResubmitMessageRequest + { + ThreadPath = threadPath, + MessageId = messageId, + UserMessageText = editedText ?? msg.Text ?? "", + OutputMessageId = outId + }, o => o.WithTarget(new Address(threadPath))); + }); + })); + + return (UiControl?)Controls.Stack + .WithStyle("max-width: 100%; padding: 12px 16px; border-radius: 12px; border-bottom-right-radius: 4px; " + + "background: var(--neutral-layer-4); border-inline-end: 3px solid var(--accent-fill-rest); " + + "margin-bottom: 12px;") + .WithView(Controls.Html("
Edit message
")) + .WithView(editor) + .WithView(buttonRow); + }); + } + /// /// Builds the Overview for messages. Role/author are static from the initial message. /// Text and tool calls are data-bound via JsonPointerReference. @@ -201,7 +290,8 @@ private static UiControl BuildMessageOverview( .WithTimestamp(msg.Timestamp) .WithText(new JsonPointerReference($"{dataPointer}/text")) .WithToolCalls(new JsonPointerReference($"{dataPointer}/toolCalls")) - .WithThreadPath(threadPath); + .WithThreadPath(threadPath) + .WithMessageId(messageId); // Action buttons — small stealth icon buttons, right-aligned // Hidden during execution via CSS :has() on the parent container @@ -213,30 +303,32 @@ private static UiControl BuildMessageOverview( if (isUser) { actionRow = actionRow - .WithView(Controls.Button("") - .WithIconStart(FluentIcons.Edit(IconSize.Size16)) - .WithAppearance(Appearance.Stealth) - .WithLabel("Edit") - .WithClickAction(_ => - { - host.Hub.Post(new EditMessageRequest - { - ThreadPath = threadPath, - MessageId = messageId, - MessageText = msg.Text - }, o => o.WithTarget(new Address(threadPath))); - })) .WithView(Controls.Button("") .WithIconStart(FluentIcons.ArrowSync(IconSize.Size16)) .WithAppearance(Appearance.Stealth) .WithLabel("Resubmit") .WithClickAction(_ => { + var outId = Guid.NewGuid().ToString("N")[..8]; + // Create output cell (same pattern as GUI submit) + host.Hub.Post(new CreateNodeRequest(new MeshNode(outId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, + MainNode = threadPath, + Content = new ThreadMessage + { + Role = "assistant", Text = "", + Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse + } + }), o => o.WithTarget(new Address(threadPath))); + host.Hub.Post(new ResubmitMessageRequest { ThreadPath = threadPath, MessageId = messageId, - UserMessageText = msg.Text + UserMessageText = msg.Text, + OutputMessageId = outId }, o => o.WithTarget(new Address(threadPath))); })); } @@ -372,15 +464,24 @@ private static UiControl BuildEditingOverview( .WithView(Controls.Button("Submit") .WithAppearance(Appearance.Accent) .WithIconStart(FluentIcons.Send(IconSize.Size16)) - .WithClickAction(async actx => + .WithClickAction(actx => { - var editedText = await actx.Host.Stream.GetDataStream(textDataId).FirstAsync(); - actx.Hub.Post(new ResubmitMessageRequest + actx.Host.Stream.GetDataStream(textDataId).Take(1).Subscribe(editedText => { - ThreadPath = threadPath, - MessageId = messageId, - UserMessageText = editedText ?? msg.Text ?? "" - }, o => o.WithTarget(new Address(threadPath))); + var outId = Guid.NewGuid().ToString("N")[..8]; + actx.Hub.Post(new CreateNodeRequest(new MeshNode(outId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = threadPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath))); + actx.Hub.Post(new ResubmitMessageRequest + { + ThreadPath = threadPath, + MessageId = messageId, + UserMessageText = editedText ?? msg.Text ?? "", + OutputMessageId = outId + }, o => o.WithTarget(new Address(threadPath))); + }); })); return Controls.Stack @@ -465,16 +566,6 @@ private static UiControl BuildUserMessageView(ThreadMessage message) .WithView(BuildReferenceChips(message.Text)) .WithView(Controls.Html($"
{message.Timestamp.Humanize()}
")); - // Add delegation link if present - if (!string.IsNullOrEmpty(message.DelegationPath)) - { - bubble = bubble.WithView(Controls.Stack - .WithOrientation(Orientation.Horizontal) - .WithStyle("margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--neutral-stroke-rest);") - .WithView(Controls.Icon(FluentIcons.ArrowRight(IconSize.Size16)).WithStyle("font-size: 14px;")) - .WithView(new NavLinkControl("View delegation", null, $"/{message.DelegationPath}"))); - } - return Controls.Stack .WithWidth("100%") .WithStyle("align-items: flex-end; margin-bottom: 12px;") @@ -545,16 +636,6 @@ private static UiControl BuildAgentResponseView(ThreadMessage message) .WithView(contentView) .WithView(Controls.Html($"
{message.Timestamp.Humanize()}
")); - // Add delegation link if present - if (!string.IsNullOrEmpty(message.DelegationPath)) - { - bubble = bubble.WithView(Controls.Stack - .WithOrientation(Orientation.Horizontal) - .WithStyle("margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--neutral-stroke-rest);") - .WithView(Controls.Icon(FluentIcons.ArrowRight(IconSize.Size16)).WithStyle("font-size: 14px;")) - .WithView(new NavLinkControl("View delegation", null, $"/{message.DelegationPath}"))); - } - return Controls.Stack .WithWidth("100%") .WithStyle("align-items: flex-start; margin-bottom: 12px;") diff --git a/src/MeshWeaver.AI/ThreadMessageViewModel.cs b/src/MeshWeaver.AI/ThreadMessageViewModel.cs index e329545cc..be8668ed9 100644 --- a/src/MeshWeaver.AI/ThreadMessageViewModel.cs +++ b/src/MeshWeaver.AI/ThreadMessageViewModel.cs @@ -35,7 +35,6 @@ public virtual bool Equals(ThreadMessageViewModel? other) && AuthorName == other.AuthorName && ModelName == other.ModelName && Text == other.Text - && ToolCalls.Count == other.ToolCalls.Count && ToolCalls.SequenceEqual(other.ToolCalls); } diff --git a/src/MeshWeaver.AI/ThreadNodeType.cs b/src/MeshWeaver.AI/ThreadNodeType.cs index abcbc9008..e82720c69 100644 --- a/src/MeshWeaver.AI/ThreadNodeType.cs +++ b/src/MeshWeaver.AI/ThreadNodeType.cs @@ -76,9 +76,13 @@ public static string GenerateSpeakingId(string messageText) public static MeshNode BuildThreadNode(string contextPath, string messageText, string? createdBy = null) { var speakingId = GenerateSpeakingId(messageText); + // Add _Thread partition for top-level threads. Sub-threads (delegations) + // live directly under the parent response message — no nested _Thread. var ns = string.IsNullOrEmpty(contextPath) ? ThreadPartition - : $"{contextPath}/{ThreadPartition}"; + : contextPath.Contains($"/{ThreadPartition}/") + ? contextPath + : $"{contextPath}/{ThreadPartition}"; var name = messageText.Length > 60 ? messageText[..57] + "..." : messageText; @@ -92,6 +96,53 @@ public static MeshNode BuildThreadNode(string contextPath, string messageText, s }; } + /// + /// Builds a thread node with pre-populated messages and pending execution. + /// When the thread grain activates, it auto-starts execution — no separate SubmitMessageRequest needed. + /// + public static (MeshNode Thread, string UserMsgId, string ResponseMsgId) BuildThreadWithMessages( + string contextPath, string messageText, + string? createdBy = null, string? agentName = null, + string? modelName = null, IReadOnlyList? attachments = null) + { + var speakingId = GenerateSpeakingId(messageText); + // Add _Thread partition for top-level threads. Sub-threads (delegations) + // live directly under the parent response message — no nested _Thread. + var ns = string.IsNullOrEmpty(contextPath) + ? ThreadPartition + : contextPath.Contains($"/{ThreadPartition}/") + ? contextPath + : $"{contextPath}/{ThreadPartition}"; + var name = messageText.Length > 60 + ? messageText[..57] + "..." + : messageText; + + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + var threadNode = new MeshNode(speakingId, ns) + { + Name = name, + NodeType = NodeType, + MainNode = contextPath, + Content = new Thread + { + CreatedBy = createdBy, + Messages = ImmutableList.Create(userMsgId, responseMsgId), + IsExecuting = true, + ActiveMessageId = responseMsgId, + ExecutionStartedAt = DateTime.UtcNow, + PendingUserMessage = messageText, + PendingAgentName = agentName, + PendingModelName = modelName, + PendingContextPath = contextPath, + PendingAttachments = attachments + } + }; + + return (threadNode, userMsgId, responseMsgId); + } + /// /// Checks if a MeshNode is a Thread by checking its NodeType. /// diff --git a/src/MeshWeaver.AI/ThreadViewModel.cs b/src/MeshWeaver.AI/ThreadViewModel.cs index dd588348e..239106da7 100644 --- a/src/MeshWeaver.AI/ThreadViewModel.cs +++ b/src/MeshWeaver.AI/ThreadViewModel.cs @@ -60,7 +60,8 @@ public virtual bool Equals(ThreadViewModel? other) && StreamingText == other.StreamingText && TokensUsed == other.TokensUsed && ExecutionStartedAt == other.ExecutionStartedAt - && Messages.SequenceEqual(other.Messages); + && Messages.SequenceEqual(other.Messages) + && (StreamingToolCalls ?? []).SequenceEqual(other.StreamingToolCalls ?? []); } public override int GetHashCode() @@ -78,6 +79,9 @@ public override int GetHashCode() hash.Add(ExecutionStartedAt); foreach (var msg in Messages) hash.Add(msg); + if (StreamingToolCalls != null) + foreach (var tc in StreamingToolCalls) + hash.Add(tc); return hash.ToHashCode(); } } diff --git a/src/MeshWeaver.AI/Threading/MeshDataSourceThreadManager.cs b/src/MeshWeaver.AI/Threading/MeshDataSourceThreadManager.cs index 31ef7ad7b..e71e9db0a 100644 --- a/src/MeshWeaver.AI/Threading/MeshDataSourceThreadManager.cs +++ b/src/MeshWeaver.AI/Threading/MeshDataSourceThreadManager.cs @@ -76,7 +76,6 @@ public async Task AddMessageAsync(string threadId, ChatMessage message, Cancella var threadMessage = new ThreadMessage { - Id = messageId, Role = message.Role.Value, AuthorName = message.AuthorName, Text = message.Text ?? string.Empty, diff --git a/src/MeshWeaver.AI/ToolStatusFormatter.cs b/src/MeshWeaver.AI/ToolStatusFormatter.cs index b20e243ed..1ac3f6086 100644 --- a/src/MeshWeaver.AI/ToolStatusFormatter.cs +++ b/src/MeshWeaver.AI/ToolStatusFormatter.cs @@ -29,7 +29,7 @@ public static string Format(FunctionCallContent functionCall) "NavigateTo" => FormatArg("Navigating to {0}", args, "path"), "SearchWeb" => FormatArg("Searching web for \"{0}\"", args, "query"), "FetchWebPage" => FormatArg("Fetching {0}", args, "url"), - "delegate_to_agent" => FormatArg("Delegating to {0}...", args, "agentName"), + "delegate_to_agent" => FormatDelegation(args), "handoff_to_agent" => FormatArg("Handing off to {0}...", args, "agentName"), "store_plan" => "Storing plan...", "AddComment" => FormatArg("Adding comment on \"{0}\"...", args, "selectedText"), @@ -40,6 +40,15 @@ _ when name.StartsWith("delegate_to_") => $"Delegating to {name["delegate_to_".L }; } + private static string FormatDelegation(IDictionary? args) + { + var agent = GetArg(args, "agentName"); + // Strip "Agent/" prefix for cleaner display + if (agent != null && agent.Contains('/')) + agent = agent.Split('/').Last(); + return $"Delegating to {agent ?? "Agent"}..."; + } + private static string FormatArg(string template, IDictionary? args, string key) { var value = GetArg(args, key); diff --git a/src/MeshWeaver.AI/UpdateThreadMessageContent.cs b/src/MeshWeaver.AI/UpdateThreadMessageContent.cs index b6cc89a15..ead099905 100644 --- a/src/MeshWeaver.AI/UpdateThreadMessageContent.cs +++ b/src/MeshWeaver.AI/UpdateThreadMessageContent.cs @@ -11,7 +11,7 @@ public record UpdateThreadMessageContent { public string? Text { get; init; } public ImmutableList? ToolCalls { get; init; } + public ImmutableList? UpdatedNodes { get; init; } public string? AgentName { get; init; } public string? ModelName { get; init; } - public string? DelegationPath { get; init; } } diff --git a/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor b/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor index 3ccec2dde..5e6c44b08 100644 --- a/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor +++ b/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor @@ -37,7 +37,10 @@ else @foreach (var msgId in ThreadMessages) { var cell = GetMessageCell(msgId); - + @if (cell != null) + { + + } } } else if (isCreatingThread) @@ -170,9 +173,44 @@ else } + +@if (showSubmissionProgress) +{ +
+
+ + Creating conversation... +
+
+} diff --git a/src/MeshWeaver.Blazor/Components/ThreadMessageBubbleView.razor.cs b/src/MeshWeaver.Blazor/Components/ThreadMessageBubbleView.razor.cs index e2d09a0a2..d8beff703 100644 --- a/src/MeshWeaver.Blazor/Components/ThreadMessageBubbleView.razor.cs +++ b/src/MeshWeaver.Blazor/Components/ThreadMessageBubbleView.razor.cs @@ -1,6 +1,7 @@ using System.Collections.Immutable; using System.Text.Json; using MeshWeaver.Layout; +using MeshWeaver.Messaging; using Microsoft.Extensions.Logging; namespace MeshWeaver.Blazor.Components; @@ -8,15 +9,21 @@ namespace MeshWeaver.Blazor.Components; public partial class ThreadMessageBubbleView : BlazorView { private bool IsUser => ViewModel.Role.Equals("user", StringComparison.OrdinalIgnoreCase); + private bool CanEdit => !string.IsNullOrEmpty(ViewModel.ThreadPath) && !string.IsNullOrEmpty(ViewModel.MessageId); private string? messageText; private IReadOnlyList? toolCalls; + private bool isEditing; private bool HasToolCalls => toolCalls is { Count: > 0 }; private MarkdownControl MarkdownVm => new MarkdownControl(messageText ?? "") .WithStyle("background: transparent;"); + private void StartEdit() => isEditing = true; + + private void CancelEdit() => isEditing = false; + protected override void BindData() { base.BindData(); diff --git a/src/MeshWeaver.Blazor/FileExplorer/FileBrowser.razor.cs b/src/MeshWeaver.Blazor/FileExplorer/FileBrowser.razor.cs index 99b65210e..7ca392832 100644 --- a/src/MeshWeaver.Blazor/FileExplorer/FileBrowser.razor.cs +++ b/src/MeshWeaver.Blazor/FileExplorer/FileBrowser.razor.cs @@ -183,7 +183,10 @@ private static bool ShouldDownload(string fileName) var extension = Path.GetExtension(fileName).ToLowerInvariant(); return extension switch { - ".xlsx" or ".xls" or ".docx" or ".doc" or ".pptx" or ".ppt" or ".zip" => true, + // Documents with converter support are previewed, not downloaded + ".docx" => false, + // Other binary formats remain download-only + ".xlsx" or ".xls" or ".doc" or ".pptx" or ".ppt" or ".zip" => true, _ => false }; } diff --git a/src/MeshWeaver.Blazor/Pages/ContentPage.razor.cs b/src/MeshWeaver.Blazor/Pages/ContentPage.razor.cs index 8c44e71ea..d630b94a6 100644 --- a/src/MeshWeaver.Blazor/Pages/ContentPage.razor.cs +++ b/src/MeshWeaver.Blazor/Pages/ContentPage.razor.cs @@ -132,7 +132,12 @@ protected override async Task OnInitializedAsync() return; ContentType = collection.GetContentType(ResolvedPath!); - if (ContentType != "text/markdown") + // Document types with converter support are rendered as markdown + if (IsConvertibleDocument(ResolvedPath!)) + { + ContentType = "text/markdown"; + } + else if (ContentType != "text/markdown") { Content = await collection.GetContentAsync(ResolvedPath!); } @@ -230,6 +235,15 @@ private void LoadMoreCsvRows() CsvVisibleRows += 50; } + /// + /// Checks if a file path points to a document that can be converted to markdown for preview. + /// + private static bool IsConvertibleDocument(string path) + { + var ext = Path.GetExtension(path).ToLowerInvariant(); + return ext is ".docx"; + } + /// /// Decodes a collection name from a URL by replacing '~' back to '/'. /// Collection names with slashes (e.g., "Submissions@Microsoft/2026") are encoded diff --git a/src/MeshWeaver.ContentCollections/AzureBlobStreamProvider.cs b/src/MeshWeaver.ContentCollections/AzureBlobStreamProvider.cs index a0b8dc8d2..d7df56032 100644 --- a/src/MeshWeaver.ContentCollections/AzureBlobStreamProvider.cs +++ b/src/MeshWeaver.ContentCollections/AzureBlobStreamProvider.cs @@ -135,6 +135,9 @@ public async Task> GetFilesAsync(string path) if (blobItem.IsBlob) { var fileName = blobItem.Blob.Name.Split('/').Last(); + // Skip .folder placeholder markers used for empty folder creation + if (fileName == ".folder") + continue; files.Add(new FileItem( ToRelativePath(blobItem.Blob.Name), fileName, @@ -158,10 +161,17 @@ public async Task SaveFileAsync(string path, string fileName, Stream content, Ca await blobClient.UploadAsync(content, overwrite: true, cancellationToken: cancellationToken); } - public Task CreateFolderAsync(string folderPath) + public async Task CreateFolderAsync(string folderPath) { - // Azure Blob Storage doesn't require explicit folder creation - return Task.CompletedTask; + // Azure Blob Storage uses virtual folders — create a zero-byte placeholder + // so the folder appears in GetBlobsByHierarchyAsync listings. + var containerClient = blobServiceClient.GetBlobContainerClient(containerName); + await containerClient.CreateIfNotExistsAsync(); + + var prefix = folderPath.TrimStart('/').TrimEnd('/'); + var markerPath = ToFullPath($"{prefix}/.folder"); + var blobClient = containerClient.GetBlobClient(markerPath); + await blobClient.UploadAsync(new BinaryData(Array.Empty()), overwrite: true); } public async Task DeleteFolderAsync(string folderPath) diff --git a/src/MeshWeaver.ContentCollections/Completion/ContentAutocompleteProvider.cs b/src/MeshWeaver.ContentCollections/Completion/ContentAutocompleteProvider.cs index b738ba0cd..19ba3d14f 100644 --- a/src/MeshWeaver.ContentCollections/Completion/ContentAutocompleteProvider.cs +++ b/src/MeshWeaver.ContentCollections/Completion/ContentAutocompleteProvider.cs @@ -6,9 +6,10 @@ namespace MeshWeaver.ContentCollections.Completion; /// /// Provides autocomplete items for content collections. -/// Returns files from all registered content collections. +/// Filters files by query relevance and scores them to compete fairly with postgres-backed results. +/// Priority scale: exact name match 3000, prefix match 2800, contains 2000. /// -public class ContentAutocompleteProvider(IContentService contentService, IMessageHub hub) : IAutocompleteProvider +public class ContentAutocompleteProvider(IContentService contentService) : IAutocompleteProvider { /// public async IAsyncEnumerable GetItemsAsync( @@ -16,38 +17,183 @@ public async IAsyncEnumerable GetItemsAsync( string? contextPath = null, [EnumeratorCancellation] CancellationToken ct = default) { - var address = hub.Address; + // Strip @ prefix and any path before the query text + var searchText = ExtractSearchText(query); - await foreach (var collection in contentService.GetCollectionsAsync().WithCancellation(ct)) + // Iterate over all configured collections + foreach (var config in contentService.GetAllCollectionConfigs()) { - IReadOnlyCollection? files = null; - try + var collection = await contentService.GetCollectionAsync(config.Name!, ct); + if (collection == null) + continue; + + await foreach (var item in EnumerateMatchingFilesAsync(collection, "/", searchText, contextPath)) { - files = await collection.GetFilesAsync("/"); + yield return item; } - catch + } + } + + private static async IAsyncEnumerable EnumerateMatchingFilesAsync( + ContentCollection collection, string path, string searchText, string? contextPath) + { + IReadOnlyCollection? files = null; + IReadOnlyCollection? folders = null; + try + { + files = await collection.GetFilesAsync(path); + folders = await collection.GetFoldersAsync(path); + } + catch + { + // Skip paths that fail to enumerate + } + + if (files != null) + { + foreach (var file in files) { - // Skip collections that fail to enumerate + var score = ScoreMatch(file.Name, searchText); + if (score <= 0 && !string.IsNullOrEmpty(searchText)) + continue; // Skip non-matching files when there's a query + + var pathWithoutLeadingSlash = file.Path.TrimStart('/'); + // For the default "content" collection, omit the collection name to avoid content:content/file + var contentPath = collection.Collection == "content" + ? pathWithoutLeadingSlash + : $"{collection.Collection}/{pathWithoutLeadingSlash}"; + var ext = Path.GetExtension(file.Name).ToLowerInvariant(); + var description = IsConvertibleDocument(ext) + ? $"{contentPath} (converts to markdown)" + : contentPath; + + // Build insert text: use relative content: path when in context + var insertText = FormatInsertText(contentPath, collection.Address, contextPath); + + yield return new AutocompleteItem( + Label: file.Name, + InsertText: insertText, + Description: description, + Category: collection.DisplayName, + Priority: score, + Kind: AutocompleteKind.File, + Path: contentPath + ); } + } - if (files != null) + if (folders != null) + { + foreach (var folder in folders) { - foreach (var file in files) + await foreach (var item in EnumerateMatchingFilesAsync(collection, folder.Path, searchText, contextPath)) { - var pathWithoutLeadingSlash = file.Path.TrimStart('/'); - var fullPath = $"{collection.Collection}/{pathWithoutLeadingSlash}"; - - // Format: addressType/addressId/content/collection/path - yield return new AutocompleteItem( - Label: file.Name, - InsertText: $"@{address}/content/{fullPath} ", - Description: fullPath, - Category: collection.DisplayName, - Priority: 0, - Kind: AutocompleteKind.File - ); + yield return item; } } } } + + /// + /// Scores a file name against the search text. + /// Returns priority values that compete with postgres ts_rank-based scores. + /// + private static int ScoreMatch(string fileName, string searchText) + { + if (string.IsNullOrEmpty(searchText)) + return 100; // Return all with low priority when no query + + var nameLower = fileName.ToLowerInvariant(); + var queryLower = searchText.ToLowerInvariant(); + var nameWithoutExt = Path.GetFileNameWithoutExtension(nameLower); + + // Exact match (with or without extension) + if (nameLower == queryLower || nameWithoutExt == queryLower) + return 3000; + + // Starts with query + if (nameLower.StartsWith(queryLower) || nameWithoutExt.StartsWith(queryLower)) + return 2800; + + // Contains query as substring + if (nameLower.Contains(queryLower)) + return 2000; + + // Word-boundary match (query matches start of a word in the name) + var words = nameWithoutExt.Split([' ', '_', '-', '.'], StringSplitOptions.RemoveEmptyEntries); + if (words.Any(w => w.StartsWith(queryLower))) + return 1500; + + return 0; // No match + } + + /// + /// Formats the insert text for autocomplete. + /// Uses relative content: path when contextPath matches the collection address. + /// Wraps in quotes if the path contains spaces. + /// + private static string FormatInsertText(string contentPath, Address? collectionAddress, string? contextPath) + { + string reference; + + // If the context is the same address as the collection, use relative path + var addressStr = collectionAddress?.ToString(); + if (!string.IsNullOrEmpty(contextPath) && + !string.IsNullOrEmpty(addressStr) && + (contextPath.Equals(addressStr, StringComparison.OrdinalIgnoreCase) || + contextPath.StartsWith(addressStr + "/", StringComparison.OrdinalIgnoreCase))) + { + reference = $"@content:{contentPath}"; + } + else if (!string.IsNullOrEmpty(addressStr)) + { + reference = $"@{addressStr}/content:{contentPath}"; + } + else + { + reference = $"@content:{contentPath}"; + } + + // Wrap in quotes if path contains spaces + if (reference.Contains(' ')) + reference = $"\"{reference}\""; + + return reference + " "; + } + + /// + /// Extracts the search text from the raw query. + /// Strips @ prefix and any content: tag prefix, keeping just the filename portion. + /// + private static string ExtractSearchText(string query) + { + if (string.IsNullOrEmpty(query)) + return ""; + + // Strip @ prefix + var text = query.TrimStart('@'); + + // If it contains content: tag, extract the part after it + var contentIndex = text.IndexOf("content:", StringComparison.OrdinalIgnoreCase); + if (contentIndex >= 0) + { + text = text[(contentIndex + "content:".Length)..]; + // Strip collection prefix if present (e.g., "collection/filename") + var lastSlash = text.LastIndexOf('/'); + if (lastSlash >= 0) + text = text[(lastSlash + 1)..]; + } + else + { + // For plain queries like "@samp", just use the text directly + // Strip any path prefix, keep last segment + var lastSlash = text.LastIndexOf('/'); + if (lastSlash >= 0) + text = text[(lastSlash + 1)..]; + } + + return text.Trim(); + } + + private static bool IsConvertibleDocument(string extension) => extension is ".docx"; } diff --git a/src/MeshWeaver.ContentCollections/ContentCollection.cs b/src/MeshWeaver.ContentCollections/ContentCollection.cs index 14ac2c4a9..037b6943a 100644 --- a/src/MeshWeaver.ContentCollections/ContentCollection.cs +++ b/src/MeshWeaver.ContentCollections/ContentCollection.cs @@ -51,6 +51,35 @@ private ISynchronizationStream CreateStream() public Task GetContentAsync(string path, CancellationToken ct = default) => provider.GetStreamAsync(path, ct); + /// + /// Returns content as text/markdown. For supported binary formats (.docx, .pptx, .xlsx), + /// converts to markdown via registered IContentTransformer. For text files, reads as-is. + /// + public async Task GetContentAsTextAsync(string path, IEnumerable? transformers = null, CancellationToken ct = default) + { + var ext = System.IO.Path.GetExtension(path).ToLowerInvariant(); + + // Try registered transformers first + var transformer = transformers?.FirstOrDefault(t => + t.SupportedExtensions.Contains(ext)); + if (transformer != null) + { + var stream = await GetContentAsync(path, ct); + if (stream == null) return null; + using (stream) + return await transformer.TransformToMarkdownAsync(stream, ct); + } + + // Fallback: read as text + var textStream = await GetContentAsync(path, ct); + if (textStream == null) return null; + using (textStream) + { + using var reader = new StreamReader(textStream); + return await reader.ReadToEndAsync(ct); + } + } + public virtual void Dispose() @@ -173,6 +202,9 @@ public virtual string GetContentType(string path) { ".json", "application/json" }, { ".csv", "text/csv" }, { ".pdf", "application/pdf" }, + { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, + { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, + { ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, { ".woff", "font/woff" }, { ".woff2", "font/woff2" }, { ".ttf", "font/ttf" }, diff --git a/src/MeshWeaver.ContentCollections/ContentCollectionsExtensions.cs b/src/MeshWeaver.ContentCollections/ContentCollectionsExtensions.cs index 0156255c4..85de08a06 100644 --- a/src/MeshWeaver.ContentCollections/ContentCollectionsExtensions.cs +++ b/src/MeshWeaver.ContentCollections/ContentCollectionsExtensions.cs @@ -3,7 +3,9 @@ using Markdig; using Markdig.Extensions.Yaml; using Markdig.Syntax; +using MeshWeaver.ContentCollections.Completion; using MeshWeaver.Data; +using MeshWeaver.Data.Completion; using MeshWeaver.Data.Serialization; using MeshWeaver.Layout; using MeshWeaver.Markdown; @@ -330,6 +332,8 @@ public static IServiceCollection AddContentService(this IServiceCollection servi services .AddScoped() .AddScoped() + .AddSingleton() + .AddScoped() .AddKeyedScoped(FileSystemStreamProvider.SourceType) .AddKeyedScoped(EmbeddedResourceStreamProvider.SourceType) .AddKeyedScoped(HubStreamProviderFactory.SourceType); diff --git a/src/MeshWeaver.ContentCollections/ContentLayoutArea.cs b/src/MeshWeaver.ContentCollections/ContentLayoutArea.cs index 014017e9d..2bc31bccd 100644 --- a/src/MeshWeaver.ContentCollections/ContentLayoutArea.cs +++ b/src/MeshWeaver.ContentCollections/ContentLayoutArea.cs @@ -6,6 +6,7 @@ using MeshWeaver.Markdown; using MeshWeaver.Mesh; using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; namespace MeshWeaver.ContentCollections; @@ -94,6 +95,36 @@ private static UiControl GetControl(string path, object content, bool isPresenta _ => false }; + private static bool IsDocumentFile(string extension) => extension is ".docx"; + + private static async Task> RenderDocumentContent( + ContentCollection collection, + IMessageHub hub, + string filePath, + CancellationToken ct) + { + try + { + var ext = Path.GetExtension(filePath).ToLowerInvariant(); + var transformer = hub.ServiceProvider.GetServices() + .FirstOrDefault(t => t.SupportedExtensions.Contains(ext)); + + if (transformer == null) + return Observable.Return(new MarkdownControl($"No converter available for {ext} files")); + + await using var stream = await collection.GetContentAsync(filePath, ct); + if (stream == null) + return Observable.Return(new MarkdownControl($"Document not found: {filePath}")); + + var markdown = await transformer.TransformToMarkdownAsync(stream, ct); + return Observable.Return(new MarkdownControl(markdown)); + } + catch (Exception ex) + { + return Observable.Return(new MarkdownControl($"Error converting document {filePath}: {ex.Message}")); + } + } + private static async Task> RenderImageContent( ContentCollection collection, string filePath, @@ -261,6 +292,12 @@ private static string GetMarkdownContent(MeshNode node) return await RenderImageContent(collection, filePath, extension, ct); } + // For binary document formats, convert to markdown via IContentTransformer + if (IsDocumentFile(extension)) + { + return await RenderDocumentContent(collection, host.Hub, filePath, ct); + } + // For other content types, use the existing GetMarkdown pipeline var contentStream = collection.GetMarkdown(filePath); if (contentStream is null) diff --git a/src/MeshWeaver.ContentCollections/DocSharpContentTransformer.cs b/src/MeshWeaver.ContentCollections/DocSharpContentTransformer.cs new file mode 100644 index 000000000..4b9c00b9b --- /dev/null +++ b/src/MeshWeaver.ContentCollections/DocSharpContentTransformer.cs @@ -0,0 +1,21 @@ +using DocSharp.Docx; + +namespace MeshWeaver.ContentCollections; + +/// +/// Transforms .docx documents to Markdown using DocSharp.Docx. +/// Registered as IContentTransformer via DI. +/// +public class DocSharpContentTransformer : IContentTransformer +{ + private static readonly HashSet Extensions = [".docx"]; + + public IReadOnlyCollection SupportedExtensions => Extensions; + + public Task TransformToMarkdownAsync(Stream input, CancellationToken ct = default) + { + var converter = new DocxToMarkdownConverter(); + var markdown = converter.ConvertToString(input); + return Task.FromResult(markdown); + } +} diff --git a/src/MeshWeaver.ContentCollections/FileContentProvider.cs b/src/MeshWeaver.ContentCollections/FileContentProvider.cs index f6db7acd9..c4e12ae5f 100644 --- a/src/MeshWeaver.ContentCollections/FileContentProvider.cs +++ b/src/MeshWeaver.ContentCollections/FileContentProvider.cs @@ -5,14 +5,17 @@ namespace MeshWeaver.ContentCollections; /// /// Implementation of IFileContentProvider that uses IContentService to access file content. +/// Automatically converts binary documents (.docx, .pptx, etc.) to markdown via IContentTransformer. /// public class FileContentProvider : IFileContentProvider { private readonly IContentService contentService; + private readonly IEnumerable transformers; - public FileContentProvider(IContentService contentService) + public FileContentProvider(IContentService contentService, IEnumerable transformers) { this.contentService = contentService; + this.transformers = transformers; } public async Task GetFileContentAsync( @@ -29,14 +32,27 @@ public async Task GetFileContentAsync( return FileContentResult.Fail($"Content collection '{collectionName}' not found"); } - await using var stream = await collection.GetContentAsync(filePath, ct); - if (stream == null) + // Try transformer for binary document formats + var ext = Path.GetExtension(filePath).ToLowerInvariant(); + var transformer = transformers.FirstOrDefault(t => t.SupportedExtensions.Contains(ext)); + if (transformer != null) + { + await using var stream = await collection.GetContentAsync(filePath, ct); + if (stream == null) + return FileContentResult.Fail($"File '{filePath}' not found in collection '{collectionName}'"); + + var markdown = await transformer.TransformToMarkdownAsync(stream, ct); + return FileContentResult.Ok(markdown); + } + + await using var textStream = await collection.GetContentAsync(filePath, ct); + if (textStream == null) { return FileContentResult.Fail($"File '{filePath}' not found in collection '{collectionName}'"); } // Read file as text - using var reader = new StreamReader(stream); + using var reader = new StreamReader(textStream); string content; if (numberOfRows.HasValue) diff --git a/src/MeshWeaver.ContentCollections/IContentTransformer.cs b/src/MeshWeaver.ContentCollections/IContentTransformer.cs new file mode 100644 index 000000000..73f3183b0 --- /dev/null +++ b/src/MeshWeaver.ContentCollections/IContentTransformer.cs @@ -0,0 +1,18 @@ +namespace MeshWeaver.ContentCollections; + +/// +/// Transforms binary content (e.g., .docx, .pptx, .xlsx) to text/markdown. +/// Registered via DI and resolved by ContentCollection.GetContentAsTextAsync. +/// +public interface IContentTransformer +{ + /// + /// File extensions this transformer handles (e.g., ".docx"). + /// + IReadOnlyCollection SupportedExtensions { get; } + + /// + /// Converts the input stream to markdown text. + /// + Task TransformToMarkdownAsync(Stream input, CancellationToken ct = default); +} diff --git a/src/MeshWeaver.ContentCollections/MeshWeaver.ContentCollections.csproj b/src/MeshWeaver.ContentCollections/MeshWeaver.ContentCollections.csproj index 722a7877a..64b99511f 100644 --- a/src/MeshWeaver.ContentCollections/MeshWeaver.ContentCollections.csproj +++ b/src/MeshWeaver.ContentCollections/MeshWeaver.ContentCollections.csproj @@ -5,6 +5,7 @@ + diff --git a/src/MeshWeaver.Data.Contract/Messages.cs b/src/MeshWeaver.Data.Contract/Messages.cs index 6741781a8..0379e128a 100644 --- a/src/MeshWeaver.Data.Contract/Messages.cs +++ b/src/MeshWeaver.Data.Contract/Messages.cs @@ -104,7 +104,14 @@ public record UnsubscribeRequest(string StreamId) : StreamMessage(StreamId); /// /// The workspace reference to retrieve data for [RequiresPermission(Permission.Read)] -public record GetDataRequest(WorkspaceReference Reference) : IRequest; +public record GetDataRequest(WorkspaceReference Reference) : IRequest +{ + /// + /// Optional MIME type to request content conversion. + /// When set to "text/markdown", binary documents (.docx, .pptx, .xlsx) are converted to markdown. + /// + public string? AcceptMimeType { get; init; } +} /// /// Response containing the requested data diff --git a/src/MeshWeaver.Data/DataContext.cs b/src/MeshWeaver.Data/DataContext.cs index b41648e32..9baaef99b 100644 --- a/src/MeshWeaver.Data/DataContext.cs +++ b/src/MeshWeaver.Data/DataContext.cs @@ -239,12 +239,7 @@ internal void OpenInitializationGate() /// private void RegisterInitializationFailureHandler(Exception initException) { - // Unwrap inner exceptions to surface the actual root cause in the error message. - // Without this, AggregateException wrapping produces doubled "Hub X failed: Hub X failed" messages. - var innerMessages = initException.InnerException is AggregateException agg - ? string.Join("; ", agg.InnerExceptions.Select(e => e.Message)) - : initException.InnerException?.Message ?? initException.Message; - var errorMessage = $"Hub '{Hub.Address}' initialization failed: {innerMessages}"; + var errorMessage = $"Hub '{Hub.Address}' initialization failed: {initException.Message}"; Hub.Register(delivery => { if (delivery.Message is DeliveryFailure) diff --git a/src/MeshWeaver.Data/DataExtensions.cs b/src/MeshWeaver.Data/DataExtensions.cs index fea161301..c5cba6787 100644 --- a/src/MeshWeaver.Data/DataExtensions.cs +++ b/src/MeshWeaver.Data/DataExtensions.cs @@ -569,6 +569,9 @@ private static async Task HandleGetDataRequest(IMessageHub hub var validationResult = await RunReadValidatorsAsync(hub, request.Message.Reference, ct); if (!validationResult.IsValid) { + var logger = hub.ServiceProvider.GetService()?.CreateLogger("MeshWeaver.Data.AccessControl"); + logger?.LogWarning("HandleGetDataRequest: Access denied for {Sender} at {Hub}, ref={Ref}: {Error}", + request.Sender, hub.Address, request.Message.Reference, validationResult.ErrorMessage); hub.Post(new GetDataResponse(null, 0) { Error = validationResult.ErrorMessage }, o => o.ResponseFor(request)); return request.Processed(); @@ -1727,11 +1730,75 @@ private static async Task HandleAutocompleteRequest( } } + // Apply relevance filtering: boost items that match the query text, + // suppress items with zero priority that don't match + var searchText = ExtractAutocompleteSearchText(query); + if (!string.IsNullOrEmpty(searchText)) + { + allItems = allItems + .Select(item => item.Priority > 0 + ? item // Provider already scored this item + : item with { Priority = ScoreAutocompleteItem(item, searchText) }) + .Where(item => item.Priority > 0) + .OrderByDescending(item => item.Priority) + .ToList(); + } + var response = new AutocompleteResponse(allItems); hub.Post(response, o => o.ResponseFor(request)); return request.Processed(); } + /// + /// Extracts the search text from an autocomplete query, stripping @ prefix and path segments. + /// + private static string ExtractAutocompleteSearchText(string query) + { + if (string.IsNullOrEmpty(query)) + return ""; + var text = query.TrimStart('@'); + // For tag queries (content:file), extract part after tag + var colonIndex = text.IndexOf(':'); + if (colonIndex >= 0) + { + text = text[(colonIndex + 1)..]; + var lastSlash = text.LastIndexOf('/'); + if (lastSlash >= 0) + text = text[(lastSlash + 1)..]; + } + else + { + // Plain query — keep last path segment + var lastSlash = text.LastIndexOf('/'); + if (lastSlash >= 0) + text = text[(lastSlash + 1)..]; + } + return text.Trim(); + } + + /// + /// Scores an autocomplete item against search text when the provider didn't set a priority. + /// Uses case-insensitive matching against Label and Description. + /// + private static int ScoreAutocompleteItem(AutocompleteItem item, string searchText) + { + var queryLower = searchText.ToLowerInvariant(); + var labelLower = item.Label?.ToLowerInvariant() ?? ""; + + if (labelLower == queryLower) + return 3000; + if (labelLower.StartsWith(queryLower)) + return 2800; + if (labelLower.Contains(queryLower)) + return 2000; + + var descLower = item.Description?.ToLowerInvariant() ?? ""; + if (descLower.Contains(queryLower)) + return 500; + + return 0; // No match — will be filtered out + } + #region Data Validators /// diff --git a/src/MeshWeaver.Data/Serialization/JsonSynchronizationStream.cs b/src/MeshWeaver.Data/Serialization/JsonSynchronizationStream.cs index 062f8a409..77f3ff1b0 100644 --- a/src/MeshWeaver.Data/Serialization/JsonSynchronizationStream.cs +++ b/src/MeshWeaver.Data/Serialization/JsonSynchronizationStream.cs @@ -147,7 +147,19 @@ internal static ISynchronizationStream CreateExternalClient + { + if (hub.RunLevel <= MessageHubRunLevel.Started) + hub.Post(new HeartBeatEvent(), o => o.WithTarget(owner)); + }) + ); + } return reduced; } diff --git a/src/MeshWeaver.Data/Validation/RlsDataValidator.cs b/src/MeshWeaver.Data/Validation/RlsDataValidator.cs index 15390558d..32b78d2b2 100644 --- a/src/MeshWeaver.Data/Validation/RlsDataValidator.cs +++ b/src/MeshWeaver.Data/Validation/RlsDataValidator.cs @@ -66,7 +66,7 @@ public async Task ValidateAsync( var userId = accessRestrictionContext.UserContext?.ObjectId ?? "(anonymous)"; var restrictionName = restriction.Name ?? "unnamed"; - _logger.LogDebug( + _logger.LogWarning( "RLS: Access denied for user {UserId} - {Operation} on {EntityType} (rule: {RuleName})", userId, context.Operation, @@ -139,7 +139,7 @@ public async Task CheckTypeAccessAsync( var allowed = await restriction.Restriction(action, type, accessRestrictionContext, ct); if (!allowed) { - _logger.LogDebug( + _logger.LogWarning( "RLS: Type-level access denied - {Action} on {Type} (rule: {RuleName})", action, type.Name, diff --git a/src/MeshWeaver.Documentation/Data/AI/Tools/MeshPlugin.md b/src/MeshWeaver.Documentation/Data/AI/Tools/MeshPlugin.md index 77612b307..eab2bd8df 100644 --- a/src/MeshWeaver.Documentation/Data/AI/Tools/MeshPlugin.md +++ b/src/MeshWeaver.Documentation/Data/AI/Tools/MeshPlugin.md @@ -2,6 +2,7 @@ Name: MeshPlugin Tools Category: Documentation Description: Complete reference for MeshPlugin tools used by AI agents +Icon: --- MeshPlugin provides tools for interacting with the mesh data graph. All paths support the `@` prefix shorthand: `@graph/org1` resolves to `graph/org1`. diff --git a/src/MeshWeaver.Documentation/Data/Architecture/AccessControl.md b/src/MeshWeaver.Documentation/Data/Architecture/AccessControl.md index 1780b0921..5ec5fb38f 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/AccessControl.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/AccessControl.md @@ -249,6 +249,54 @@ The Access Control layout area (`AccessControlArea`) provides: 3. **Add Assignment** (admin-only): Dialog with autocompleting comboboxes for Subject (User/Group search via IMeshService) and Role selection. +# Partition Access Control + +In multi-tenant PostgreSQL deployments, each organization has its own schema (partition). Access to partitions is controlled by the `partition_access` table: + +```sql +CREATE TABLE public.partition_access ( + user_id TEXT NOT NULL, + partition TEXT NOT NULL, + PRIMARY KEY (user_id, partition) +); +``` + +Populated automatically by `rebuild_user_effective_permissions()` in each partition's schema. When a user has any role in a partition, they get a `partition_access` entry. + +## Partition Access in Search + +Cross-schema search (`search_across_schemas`) enforces partition access at the SQL level. The access control clause requires: + +1. **Partition access** — user must have `partition_access` entry for the schema (always required) +2. **Node-level permission** — user must have Read permission on the node's `main_node` path + +`public_read` node types (e.g., User, Markdown) skip the node-level check but still require partition access. This prevents cross-partition data leakage — a user can't see another organization's nodes just because the node type is publicly readable. + +```sql +-- Access control: partition_access is ALWAYS required. +-- public_read only skips node-level permission checks. +WHERE partition_access_exists AND ( + public_read_node_type OR node_level_permission +) +``` + +## AI Tool Call Identity + +When AI agents execute tool calls (Get, Update, Create, etc.) during thread streaming, the user's `AsyncLocal` access context doesn't flow through the AI framework's async tool invocation chain. All tools are wrapped with `AccessContextAIFunction` (a `DelegatingAIFunction`) that restores the user's identity from `ThreadExecutionContext.UserAccessContext` before each invocation. + +This ensures tool calls run with the correct user identity for permission checks. + +## Satellite Node Permissions + +Satellite node types (Thread, Comment, ApiToken) use `GetPermissionForNodeType` to map to their required permission: + +| Node Type | Required Permission | +|-----------|-------------------| +| Thread, ThreadMessage | `Permission.Thread` | +| Comment | `Permission.Comment` | +| ApiToken | `Permission.Api` | +| All others | `Permission.Create` | + # PostgreSQL Integration For PostgreSQL deployments, a denormalized `user_effective_permissions` table enables fast query-time permission checks. A trigger on `mesh_nodes` automatically rebuilds this table when AccessAssignment or GroupMembership nodes change. diff --git a/src/MeshWeaver.Documentation/Data/Architecture/AsynchronousCalls.md b/src/MeshWeaver.Documentation/Data/Architecture/AsynchronousCalls.md new file mode 100644 index 000000000..cd9d84186 --- /dev/null +++ b/src/MeshWeaver.Documentation/Data/Architecture/AsynchronousCalls.md @@ -0,0 +1,180 @@ +# Asynchronous Calls in MeshWeaver + +MeshWeaver uses a **truly asynchronous** message-passing model. This is fundamentally different from C#'s `async/await` pattern, which is better described as "fake async" — you still block the calling context waiting for a result. + +## The T-Shirt Analogy + +When you order a t-shirt online, you don't stand next to the mailbox until it arrives. Your life continues. The t-shirt shows up later, and you deal with it then. + +**Truly async (MeshWeaver pattern):** +```csharp +// Post the request — fire and forget +hub.Post(new MyRequest(), o => o.WithTarget(address)); + +// Register a callback — triggered when the answer returns +hub.RegisterCallback(delivery, response => +{ + // Handle response here — your "mailbox notification" + return response; +}); + +// Your code continues immediately — no blocking +return delivery.Processed(); +``` + +**Fake async (C# async/await):** +```csharp +// You ARE standing at the mailbox +var response = await hub.AwaitResponse(request); +// Nothing else happens until the response arrives +``` + +## Why `await` Deadlocks in Hub Handlers + +The message hub processes messages sequentially through a single-threaded `ActionBlock`. When a handler calls `await`, it blocks the action block waiting for a response. But that response is itself a message that needs to be processed by the same action block — which is blocked. **Deadlock.** + +``` +Handler runs on ActionBlock + → await AwaitResponse(request) + → ActionBlock is blocked waiting + → Response message arrives + → Cannot be processed — ActionBlock is busy + → DEADLOCK +``` + +This applies to: +- `await hub.AwaitResponse(...)` — blocks the hub +- `await someTask` — blocks the hub scheduler +- `hub.InvokeAsync(...)` — schedules work on the blocked scheduler +- `workspace.GetStream().Subscribe(...)` — if the stream observes on the hub scheduler, the emission is queued behind the blocked handler + +## The Observable Pattern + +Use `IMeshService` to get into reactive/observable contexts. Observables are inherently truly async — you subscribe and get notified when data is available. + +### Creating Nodes (Non-Blocking) + +Fire-and-forget node creation. State updates go in the **handler body** (runs on the grain scheduler), not in the Subscribe callback: + +```csharp +// Fire-and-forget — no callback needed for state updates +meshService.CreateNode(new MeshNode(id, namespace) +{ + NodeType = "MyType", + Content = new MyContent { ... } +}).Subscribe( + _ => logger.LogInformation("Node created"), + error => logger.LogError(error, "Node creation failed")); + +// State update in the handler body (grain scheduler) — safe +hub.GetWorkspace().UpdateMeshNode(node => node with +{ + Content = content with { Messages = content.Messages.Add(id) } +}); + +// Handler returns immediately +return delivery.Processed(); +``` + +### CRITICAL: Never Do State Updates in Subscribe Callbacks + +Subscribe callbacks run on **arbitrary threads**. State updates (`workspace.UpdateMeshNode`) require the hub's scheduler. Mixing these causes deadlocks — this is not framework-specific, it's a fundamental consequence of truly async programming: you don't control which thread a callback runs on. + +```csharp +// WRONG — callback runs on unknown thread, state update needs hub scheduler: +meshService.CreateNode(node).Subscribe(_ => +{ + workspace.UpdateMeshNode(n => ...); // ← deadlock: wrong thread +}); + +// CORRECT — separate concerns: fire-and-forget for I/O, state update in handler body: +meshService.CreateNode(node).Subscribe(); // fire-and-forget +hub.GetWorkspace().UpdateMeshNode(n => ...); // handler body = hub scheduler +``` + +The principle: **I/O is fire-and-forget, state changes happen where you control the thread.** This is true for any actor-based or message-passing system. + +## Post + RegisterCallback Pattern + +For request-response flows where you need the result but can't block: + +```csharp +// 1. Post the request (returns immediately) +var delivery = hub.Post(new CreateNodeRequest(node), o => o.WithTarget(address)); + +// 2. Register a callback for the response (non-blocking) +hub.RegisterCallback((IMessageDelivery)delivery, response => +{ + if (response is IMessageDelivery cnr) + { + // Handle success + tcs.TrySetResult(cnr.Message); + } + return response; +}); + +// 3. Return immediately — callback fires later +return delivery.Processed(); +``` + +## Workspace Updates (Non-Blocking) + +`workspace.UpdateMeshNode` applies an update function to the current node state. It posts the update to the data stream — no blocking, no subscription: + +```csharp +// Read current state and update atomically — no stream subscription needed +workspace.UpdateMeshNode(node => +{ + var content = node.Content as MyContent ?? new MyContent(); + return node with + { + Content = content with { Status = "updated" } + }; +}); +``` + +## Rules Summary + +| Pattern | Safe in Handlers? | Notes | +|---------|-------------------|-------| +| `hub.Post(...)` | Yes | Fire-and-forget, safe from any thread | +| `hub.RegisterCallback(...)` | Yes | Non-blocking callback registration | +| `meshService.CreateNode(...).Subscribe()` | Yes | Fire-and-forget, no callback logic | +| `workspace.UpdateMeshNode(...)` in handler body | Yes | Runs on grain scheduler | +| `workspace.UpdateMeshNode(...)` in Subscribe callback | **NO** | Wrong thread in Orleans, deadlocks | +| `meshService.QueryAsync(...)` | **NO** | Blocks waiting for response | +| `await hub.AwaitResponse(...)` | **NO** | Deadlocks the hub scheduler | +| `await someTask` | **NO** | Blocks the hub scheduler | +| `hub.InvokeAsync(...)` | **NO** | Schedules on potentially blocked scheduler | +| `stream.Subscribe(...)` | **Risky** | May deadlock if stream observes on hub scheduler | + +## When async/await IS Safe + +`async/await` is safe in contexts that don't run on the hub's scheduler: +- Blazor component event handlers (`OnClick`, `OnInitializedAsync`) +- HTTP middleware and API controllers +- Background services and hosted services +- Test code + +The rule is simple: **if your code runs inside a hub message handler (registered via `.WithHandler()`), never await.** + +## Blocking Execution (AI Streaming) + +Sometimes you genuinely need long-running I/O — for example, streaming an AI response. This uses a **hosted hub** (`_Exec`) that runs the blocking work on its own thread via `hub.InvokeAsync`. But even here: + +- All **state updates** (workspace, thread content) go through the **parent hub** (`parentHub.GetWorkspace().UpdateMeshNode(...)`, `parentHub.Post(...)`) +- All **messages** go through the parent hub — never post to the execution hub +- The execution hub is purely for hosting the blocking I/O — it should never own state + +```csharp +// In HandleSubmitMessage (runs on thread hub): +var executionHub = hub.GetHostedHub(new Address($"{hub.Address}/_Exec"), ...); +executionHub.Post(request); // Only message to execution hub: start the work + +// In ExecuteMessageAsync (runs on _Exec hub): +var parentHub = hub.Configuration.ParentHub!; +parentHub.Post(new UpdateThreadMessageContent { ... }); // State via parent hub +parentHub.GetWorkspace().UpdateMeshNode(...); // Workspace via parent hub +``` + +The parent hub's scheduler is free (the handler returned `delivery.Processed()` immediately). State updates and callbacks process normally on it. diff --git a/src/MeshWeaver.Documentation/Data/Architecture/DataAccessPatterns.md b/src/MeshWeaver.Documentation/Data/Architecture/DataAccessPatterns.md index ed09cd076..ab843b608 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/DataAccessPatterns.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/DataAccessPatterns.md @@ -2,6 +2,7 @@ Name: Data Access Patterns Category: Documentation Description: How to correctly read, create, update, and delete mesh nodes and data from application code +Icon: --- MeshWeaver enforces strict data access patterns to ensure security (RLS validation), consistency, and traceability. Application code must **never** use `IMeshStorage` or `IMeshCatalog` directly — these are internal infrastructure interfaces. diff --git a/src/MeshWeaver.Documentation/Data/Architecture/SatelliteEntityPatterns.md b/src/MeshWeaver.Documentation/Data/Architecture/SatelliteEntityPatterns.md index fdb4d4bd6..494fbe2a5 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/SatelliteEntityPatterns.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/SatelliteEntityPatterns.md @@ -2,6 +2,7 @@ Name: Satellite Entity Patterns Category: Architecture Description: Implementation and test patterns for satellite entities (comments, threads, tracked changes) — data model, handlers, workspace updates, and Orleans testing +Icon: --- Satellite entities (Comments, Threads, Tracked Changes) follow a specific pattern for both handler implementation and testing. This document covers the non-blocking handler pattern, the parent-child tracking pattern, and the reactive test verification approach. diff --git a/src/MeshWeaver.Documentation/Data/Architecture/SatelliteNodePatterns.md b/src/MeshWeaver.Documentation/Data/Architecture/SatelliteNodePatterns.md index fcbdf8b39..19df0f571 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/SatelliteNodePatterns.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/SatelliteNodePatterns.md @@ -1,3 +1,10 @@ +--- +Name: Satellite Node Patterns +Category: Architecture +Description: Architecture patterns for parent-child node hierarchies with hub ownership and persistence +Icon: +--- + # Satellite Node Patterns Satellite nodes are nodes whose `MainNode` points to a parent node. They form hierarchical structures like Threads with Messages, or Documents with Comments. This document describes the architecture patterns for implementing satellite nodes with children. diff --git a/src/MeshWeaver.Documentation/Data/Architecture/WorkspaceReferences.md b/src/MeshWeaver.Documentation/Data/Architecture/WorkspaceReferences.md index b0ee7a31b..8c9ac40ec 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/WorkspaceReferences.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/WorkspaceReferences.md @@ -2,6 +2,7 @@ Name: Workspace References & Streaming Category: Documentation Description: How to register custom workspace references, reducers, and patch functions for typed stream access +Icon: --- MeshWeaver uses **workspace references** to define typed views over the underlying `EntityStore` data. Each reference type maps to a specific reduction of the data and can optionally support write-back via **patch functions**. diff --git a/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md b/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md index 027836c03..f57d5aee9 100644 --- a/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md +++ b/src/MeshWeaver.Documentation/Data/DataMesh/DataConfiguration.md @@ -12,8 +12,6 @@ This guide explains how to configure data in message hubs, including data source MeshWeaver provides flexible data configuration patterns: - **AddSource**: Configure local data sources with optional initialization - **AddHubSource**: Synchronize data from parent or related hubs -- **AddPartitionedHubSource**: Aggregate data from multiple child hubs by partition -- **WithVirtualDataSource**: Load data from reactive streams (mesh queries, node content, etc.) - **WithInitialData**: Seed data sources with predefined records # Data Model Relationships @@ -210,91 +208,3 @@ When a `DataChangeRequest` arrives at the Todo hub, changes are persisted to sto ``` This configuration enables the Todo hub to access Status reference data from its parent Project hub, ensuring consistent status options across the hierarchy. - -# Partitioned Hub Data Source - -## AddPartitionedHubSource - -Use `AddPartitionedHubSource` to aggregate data from multiple child hubs into a parent hub. Each child hub owns its own data; the parent reads from them as live streams. This is the data mesh pattern for cross-domain data composition. - -### When to Use - -- A group/parent hub needs to consolidate data from multiple domain hubs -- Each domain hub independently owns and manages its data -- The consolidated view should update reactively when any domain's data changes - -### Configuration Example - -```csharp -config => config - .AddData(data => data - .AddPartitionedHubSource
( - c => c.WithType( - row => (Address)("Namespace/" + row.Partition + "/Analysis")) - .InitializingPartitions( - (Address)"Namespace/PartitionA/Analysis", - (Address)"Namespace/PartitionB/Analysis"))) -``` - -The `WithType` lambda maps each data row to the hub address that owns it. `InitializingPartitions` lists the addresses to subscribe to on startup. - -### Data Flow - -```mermaid -graph LR - A[Hub A
owns data] -->|stream| P[Parent Hub
PartitionedHubDataSource] - B[Hub B
owns data] -->|stream| P - C[Hub C
owns data] -->|stream| P - P --> V[Consolidated View] - - classDef domain fill:#e8f0fe,stroke:#4285f4,color:#333 - classDef parent fill:#e6f4ea,stroke:#34a853,color:#333 - class A,B,C domain - class P,V parent -``` - -Adding a new partition is a single address — no new ETL pipeline, no data copying. - -# Virtual Data Sources - -## WithVirtualDataSource - -Use `WithVirtualDataSource` to load data from reactive `IObservable` streams — e.g., mesh node queries, computed data, or embedded node content. - -### Loading from Mesh Node Queries - -```csharp -config => config - .AddData(data => data - .WithVirtualDataSource("ReferenceData", vs => vs - .WithVirtualType(workspace => - { - var meshQuery = workspace.Hub.ServiceProvider - .GetRequiredService(); - return meshQuery.ObserveQuery( - MeshQueryRequest.FromQuery("nodeType:ExchangeRate")); - }))) -``` - -### Loading from Embedded Node Content - -When data is stored as structured arrays inside a MeshNode's `Content` field, load it by querying the node and extracting the embedded data: - -```csharp -config => config - .WithContentType() - .AddData(data => data - .WithVirtualDataSource("LocalData", vs => vs - .WithVirtualType(workspace => - LoadDataFromContent(workspace)))) -``` - -This pattern is deployment-mode independent — the same code works whether the MeshNode is stored on the filesystem, in PostgreSQL, or in Cosmos DB. - -### When to Use Which Pattern - -| Pattern | Use When | -|---------|----------| -| **Individual MeshNodes** | Each row is an independently editable entity (users, products, orders) | -| **Embedded content array** | Data is loaded as a unit, read-heavy, updated as a batch (datacubes, time series) | -| **External files (CSV, etc.)** | Legacy integration only — not recommended for new development (filesystem-dependent) | diff --git a/src/MeshWeaver.Documentation/Data/DataMesh/NodeOperations.md b/src/MeshWeaver.Documentation/Data/DataMesh/NodeOperations.md index 5a1d788dd..062bfb127 100644 --- a/src/MeshWeaver.Documentation/Data/DataMesh/NodeOperations.md +++ b/src/MeshWeaver.Documentation/Data/DataMesh/NodeOperations.md @@ -2,6 +2,7 @@ Name: Node Operations Category: Documentation Description: Export, Import, Copy, and Move operations for mesh nodes +Icon: --- MeshWeaver provides built-in operations for transferring node subtrees between locations, exporting to files, and importing from external sources. These are accessible from the **Actions** sub-menu on any node. diff --git a/src/MeshWeaver.Documentation/Data/GUI/DataBinding/ItemTemplate.md b/src/MeshWeaver.Documentation/Data/GUI/DataBinding/ItemTemplate.md index 9c93763a3..392118774 100644 --- a/src/MeshWeaver.Documentation/Data/GUI/DataBinding/ItemTemplate.md +++ b/src/MeshWeaver.Documentation/Data/GUI/DataBinding/ItemTemplate.md @@ -2,6 +2,7 @@ Name: Item Templates Category: Documentation Description: How to render collections of items using data-bound ItemTemplateControl with BindMany +Icon: --- `ItemTemplateControl` repeats a view template for each item in a collection. It is the MeshWeaver equivalent of a "for-each" renderer, binding each element of an array to a template view. diff --git a/src/MeshWeaver.Documentation/Data/GUI/NodeMenu.md b/src/MeshWeaver.Documentation/Data/GUI/NodeMenu.md index 87eef49ec..d13b360ef 100644 --- a/src/MeshWeaver.Documentation/Data/GUI/NodeMenu.md +++ b/src/MeshWeaver.Documentation/Data/GUI/NodeMenu.md @@ -2,6 +2,7 @@ Name: Node Menu Items Category: Documentation Description: How node types register custom menu items in the portal's context menu, including hierarchical sub-menus +Icon: --- The portal's node context menu (cube icon) is fully data-driven. Menu items are registered in the node's `HubConfiguration` via `IAsyncEnumerable` providers and rendered during the layout pipeline. A predicate-based renderer evaluates all providers and stores results at `$Menu` in the entity store (same pattern as `$Dialog`). The portal reads `$Menu` from the layout stream -- no separate RPC needed. diff --git a/src/MeshWeaver.Documentation/Data/GUI/SidePanel.md b/src/MeshWeaver.Documentation/Data/GUI/SidePanel.md index 82b229d64..21176d9a0 100644 --- a/src/MeshWeaver.Documentation/Data/GUI/SidePanel.md +++ b/src/MeshWeaver.Documentation/Data/GUI/SidePanel.md @@ -2,6 +2,7 @@ Name: Side Panel & Main Panel Category: Documentation Description: How the side panel and main panel work together for multitasking, chat, and navigation +Icon: --- The portal uses a split-view layout with a **main panel** and a collapsible **side panel**. The side panel is primarily used for AI chat threads but can display any content. The main panel shows the current page content. diff --git a/src/MeshWeaver.Fixture/LoggingBuilderExtensions.cs b/src/MeshWeaver.Fixture/LoggingBuilderExtensions.cs index 216e93737..556ff1f2c 100644 --- a/src/MeshWeaver.Fixture/LoggingBuilderExtensions.cs +++ b/src/MeshWeaver.Fixture/LoggingBuilderExtensions.cs @@ -126,7 +126,9 @@ public void Log( Func formatter ) { - if (testOutputHelperAccessor.OutputHelper == null) + var outputHelper = testOutputHelperAccessor.OutputHelper + ?? XUnitFileOutputRegistry.GetAnyActiveOutputHelper(); + if (outputHelper == null) return; if (!IsEnabled(logLevel)) return; @@ -150,7 +152,7 @@ public void Log( #pragma warning disable RCS1075 // Avoid empty catch clause that catches System.Exception try { - testOutputHelperAccessor.OutputHelper.WriteLine(sb.ToString()); + outputHelper.WriteLine(sb.ToString()); } catch (Exception) { } #pragma warning restore RCS1075 // Avoid empty catch clause that catches System.Exception diff --git a/src/MeshWeaver.Graph/Configuration/ApiTokenNodeType.cs b/src/MeshWeaver.Graph/Configuration/ApiTokenNodeType.cs index 6d89dd8a0..897c00a56 100644 --- a/src/MeshWeaver.Graph/Configuration/ApiTokenNodeType.cs +++ b/src/MeshWeaver.Graph/Configuration/ApiTokenNodeType.cs @@ -1,5 +1,7 @@ +using System.Collections.Concurrent; using System.Text.Json; using MeshWeaver.Data; +using MeshWeaver.Graph.Security; using MeshWeaver.Mesh; using MeshWeaver.Mesh.Security; using MeshWeaver.Mesh.Services; @@ -10,23 +12,31 @@ namespace MeshWeaver.Graph.Configuration; /// /// Provides configuration for ApiToken nodes in the graph. -/// ApiToken nodes are system-managed — excluded from search and create contexts. -/// Handles ValidateTokenRequest to authenticate API tokens via the message hub. +/// Tokens are satellites of User nodes, stored at User/{userId}/_Api/{hashPrefix}. +/// An index at ApiToken/{hashPrefix} enables fast validation routing. +/// Creation uses standard CreateNodeRequest with nodeType=ApiToken — the RLS validator +/// maps this to Permission.Api via GetPermissionForNodeType. /// public static class ApiTokenNodeType { public const string NodeType = "ApiToken"; + private static readonly ConcurrentDictionary ValidationCache = new(); + private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(5); public static TBuilder AddApiTokenType(this TBuilder builder) where TBuilder : MeshBuilder { builder.AddMeshNodes(CreateMeshNode()); builder.AddAutocompleteExcludedTypes(NodeType); + // Access control: GetPermissionForNodeType maps "ApiToken" → Permission.Api + // The RLS validator checks Permission.Api on the MainNode (User path) + // Same pattern as Thread → Permission.Thread and Comment → Permission.Comment return builder; } public static MeshNode CreateMeshNode() => new(NodeType) { Name = "API Token", + IsSatelliteType = true, ExcludeFromContext = new HashSet { "search", "create" }, AssemblyLocation = typeof(ApiTokenNodeType).Assembly.Location, HubConfiguration = config => config @@ -38,10 +48,8 @@ public static TBuilder AddApiTokenType(this TBuilder builder) where TB }; /// - /// Validates an API token. The handler runs on the token's hosted hub (ApiToken/{hashPrefix}). - /// Uses IStorageService to bypass RLS — token validation happens before any user is logged in. - /// Supports both new format (ApiTokenIndex pointer -> User/{userId}/ApiToken/{hash}) - /// and legacy format (full ApiToken at index path). + /// Validates an API token. Routes to ApiToken/{hashPrefix}, follows index to User/{userId}/_Api/{hash}. + /// Results are cached for 5 minutes. /// private static async Task HandleValidateToken( IMessageHub hub, @@ -56,8 +64,17 @@ private static async Task HandleValidateToken( return request.Processed(); } - // Load the token node directly from persistence (bypasses RLS) - var hubPath = hub.Address.ToString(); + var hash = ValidateTokenRequest.HashToken(rawToken); + + // Check cache first + if (ValidationCache.TryGetValue(hash, out var cached) && cached.ExpiresAt > DateTimeOffset.UtcNow) + { + hub.Post(cached.Response, o => o.ResponseFor(request)); + return request.Processed(); + } + + // Load from persistence (bypasses RLS) + var hubPath = hub.Address.Path; var persistenceCore = hub.ServiceProvider.GetService(); if (persistenceCore == null) { @@ -72,14 +89,12 @@ private static async Task HandleValidateToken( return request.Processed(); } - // Check if this is an index pointer (new format) or a legacy full token - var hash = ValidateTokenRequest.HashToken(rawToken); + // Check if this is an index pointer or a legacy full token var index = node.Content as ApiTokenIndex ?? ExtractApiTokenIndex(node, hub.JsonSerializerOptions); ApiToken? apiToken; if (index != null) { - // New format: verify hash against index, then follow pointer to full token if (!string.Equals(index.TokenHash, hash, StringComparison.OrdinalIgnoreCase)) { hub.Post(ValidateTokenResponse.Fail("Invalid token"), o => o.ResponseFor(request)); @@ -91,7 +106,6 @@ private static async Task HandleValidateToken( } else { - // Legacy format: full ApiToken at index path apiToken = node.Content as ApiToken ?? ExtractApiToken(node, hub.JsonSerializerOptions); } @@ -101,7 +115,6 @@ private static async Task HandleValidateToken( return request.Processed(); } - // Verify hash matches if (!string.Equals(apiToken.TokenHash, hash, StringComparison.OrdinalIgnoreCase)) { hub.Post(ValidateTokenResponse.Fail("Invalid token"), o => o.ResponseFor(request)); @@ -120,43 +133,28 @@ private static async Task HandleValidateToken( return request.Processed(); } - hub.Post( - ValidateTokenResponse.Ok(apiToken.UserId, apiToken.UserName, apiToken.UserEmail), - o => o.ResponseFor(request)); + var response = ValidateTokenResponse.Ok(apiToken.UserId, apiToken.UserName, apiToken.UserEmail); + ValidationCache[hash] = (response, DateTimeOffset.UtcNow + CacheDuration); + + hub.Post(response, o => o.ResponseFor(request)); return request.Processed(); } private static ApiToken? ExtractApiToken(MeshNode? node, JsonSerializerOptions options) { - if (node?.Content is JsonElement jsonElement) - { - try - { - return JsonSerializer.Deserialize(jsonElement.GetRawText(), options); - } - catch - { - return null; - } - } - return null; + if (node?.Content is not JsonElement jsonElement) return null; + try { return JsonSerializer.Deserialize(jsonElement.GetRawText(), options); } + catch { return null; } } private static ApiTokenIndex? ExtractApiTokenIndex(MeshNode? node, JsonSerializerOptions options) { - if (node?.Content is JsonElement jsonElement) + if (node?.Content is not JsonElement jsonElement) return null; + try { - try - { - var index = JsonSerializer.Deserialize(jsonElement.GetRawText(), options); - // Distinguish from legacy ApiToken: index has TokenPath set - return !string.IsNullOrEmpty(index?.TokenPath) ? index : null; - } - catch - { - return null; - } + var index = JsonSerializer.Deserialize(jsonElement.GetRawText(), options); + return !string.IsNullOrEmpty(index?.TokenPath) ? index : null; } - return null; + catch { return null; } } } diff --git a/src/MeshWeaver.Graph/Configuration/UserNodeType.cs b/src/MeshWeaver.Graph/Configuration/UserNodeType.cs index 69fb971fc..df315c67c 100644 --- a/src/MeshWeaver.Graph/Configuration/UserNodeType.cs +++ b/src/MeshWeaver.Graph/Configuration/UserNodeType.cs @@ -36,7 +36,8 @@ public static TBuilder AddUserType(this TBuilder builder) where TBuild builder.ConfigureServices(services => { services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(sp => + new UserAccessRule(sp.GetService() ?? new NullSecurityService())); services.AddSingleton(sp => new UserScopeGrantHandler( sp.GetService() ?? new NullSecurityService())); @@ -119,29 +120,39 @@ private static MessageHubConfiguration WithPortalCreate(this MessageHubConfigura /// DI-registered access rule for User nodes — reliable fallback when hub-config /// rules haven't been cached yet (e.g. during first onboarding). ///
- private class UserAccessRule : INodeTypeAccessRule + private class UserAccessRule(ISecurityService securityService) : INodeTypeAccessRule { public string NodeType => UserNodeType.NodeType; public IReadOnlyCollection SupportedOperations => [NodeOperation.Create, NodeOperation.Read, NodeOperation.Update]; - public Task HasAccessAsync(NodeValidationContext context, string? userId, CancellationToken ct = default) + public async Task HasAccessAsync(NodeValidationContext context, string? userId, CancellationToken ct = default) { - // Read: only the User node itself is publicly readable (path == "User/{id}"). - // Children (threads, activities, etc.) require explicit access. + // Read: + // - NodeType definition ("User"): always readable + // - Direct user nodes ("User/{id}"): publicly readable (any authenticated caller) + // - Children (threads, activities, etc.): delegate to ISecurityService if (context.Operation == NodeOperation.Read) { var nodePath = context.Node.Path; - if (!string.IsNullOrEmpty(nodePath) - && nodePath.StartsWith("User/", StringComparison.OrdinalIgnoreCase) + if (string.IsNullOrEmpty(nodePath)) + return false; + // NodeType definition + if (nodePath.Equals("User", StringComparison.OrdinalIgnoreCase)) + return true; + // Direct user nodes are publicly readable + if (nodePath.StartsWith("User/", StringComparison.OrdinalIgnoreCase) && !nodePath["User/".Length..].Contains('/')) - return Task.FromResult(true); - return Task.FromResult(false); + return !string.IsNullOrEmpty(userId); + // Children: delegate to standard permission checks + if (string.IsNullOrEmpty(userId)) + return false; + return await securityService.HasPermissionAsync(nodePath, userId, Permission.Read, ct); } if (string.IsNullOrEmpty(userId)) - return Task.FromResult(false); + return false; // Update: user can edit their own node if (context.Operation == NodeOperation.Update) @@ -152,12 +163,12 @@ public Task HasAccessAsync(NodeValidationContext context, string? userId, var userScopePath = $"User/{userId}"; if (nodePath.Equals(userScopePath, StringComparison.OrdinalIgnoreCase) || nodePath.StartsWith(userScopePath + "/", StringComparison.OrdinalIgnoreCase)) - return Task.FromResult(true); + return true; } } // Create/Update: portal namespace identities (onboarding flow) - return Task.FromResult(IsPortalIdentity(userId)); + return IsPortalIdentity(userId); } } diff --git a/src/MeshWeaver.Graph/MeshDataSource.cs b/src/MeshWeaver.Graph/MeshDataSource.cs index 2e90472d7..ba2b10a2c 100644 --- a/src/MeshWeaver.Graph/MeshDataSource.cs +++ b/src/MeshWeaver.Graph/MeshDataSource.cs @@ -149,7 +149,11 @@ private static ChangeItem ReduceToMeshNode( var change = current.Updates.FirstOrDefault(); if (change == null) - return null!; + { + // Patch with no matching Updates — fall back to full value instead of + // returning null (which silently drops the emission and blocks live updates). + return new(node, current.StreamId, current.Version); + } return new(change.Value as MeshNode, current.ChangedBy, current.StreamId, ChangeType.Patch, current.Version, [change]); } diff --git a/src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs b/src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs index d6fc929df..a5f18a0c7 100644 --- a/src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs +++ b/src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs @@ -725,7 +725,8 @@ public static UiControl Children(LayoutAreaHost host, RenderingContext _) .WithRenderMode(MeshSearchRenderMode.Grouped) // No explicit grouping - defaults to NodeType which gives meaningful labels .WithSectionCounts(true) - .WithItemLimit(10) + .WithItemLimit(50) + .WithMaxRows(3) .WithCollapsibleSections(true) .WithCreateHref($"/{hubPath}/{CreateNodeArea}?type=Markdown&namespace={Uri.EscapeDataString(hubPath)}"); } diff --git a/src/MeshWeaver.Graph/NodeTypeLayoutAreas.cs b/src/MeshWeaver.Graph/NodeTypeLayoutAreas.cs index 7e15a69d7..50fcddd03 100644 --- a/src/MeshWeaver.Graph/NodeTypeLayoutAreas.cs +++ b/src/MeshWeaver.Graph/NodeTypeLayoutAreas.cs @@ -159,7 +159,8 @@ private static UiControl BuildNodeTypeDetailsContent(this LayoutAreaHost host, M .WithShowLoadingIndicator(false) .WithRenderMode(MeshSearchRenderMode.Grouped) .WithSectionCounts(true) - .WithItemLimit(10) + .WithItemLimit(50) + .WithMaxRows(3) .WithCollapsibleSections(true) .WithCreateHref(BuildCreateHref(hubPath, typeDef)))); diff --git a/src/MeshWeaver.Graph/Security/RlsNodeValidator.cs b/src/MeshWeaver.Graph/Security/RlsNodeValidator.cs index faf144acf..15c7fb424 100644 --- a/src/MeshWeaver.Graph/Security/RlsNodeValidator.cs +++ b/src/MeshWeaver.Graph/Security/RlsNodeValidator.cs @@ -40,8 +40,13 @@ public RlsNodeValidator( public async Task ValidateAsync(NodeValidationContext context, CancellationToken ct = default) { - // Self-access: hubs always have full control of their own nodes + // System identity bypass: SecurityService uses WellKnownUsers.System for internal + // operations (creating AccessAssignment, PartitionAccessPolicy nodes). + // These must not be blocked by the permissions they manage. var userId = GetUserId(context); + if (userId == WellKnownUsers.System) + return NodeValidationResult.Valid(); + if (!string.IsNullOrEmpty(userId)) { // Check MainNode match (original check) @@ -112,7 +117,7 @@ public async Task ValidateAsync(NodeValidationContext cont return NodeValidationResult.Valid(); } - _logger.LogDebug( + _logger.LogWarning( "RLS: Custom access rule denied {UserId} - {Operation} on {Path} (NodeType: {NodeType})", userId ?? "(anonymous)", context.Operation, context.Node.Path, context.Node.NodeType); return NodeValidationResult.Unauthorized( @@ -150,7 +155,7 @@ public async Task ValidateAsync(NodeValidationContext cont { var displayUserId = userId ?? "(anonymous)"; - _logger.LogDebug( + _logger.LogWarning( "RLS: Access denied for user {UserId} - {Operation} on {Path} requires {Permission}", displayUserId, context.Operation, diff --git a/src/MeshWeaver.Graph/UserActivityLayoutAreas.cs b/src/MeshWeaver.Graph/UserActivityLayoutAreas.cs index eccf4a0dd..35a2cf648 100644 --- a/src/MeshWeaver.Graph/UserActivityLayoutAreas.cs +++ b/src/MeshWeaver.Graph/UserActivityLayoutAreas.cs @@ -37,13 +37,11 @@ public static MessageHubConfiguration AddUserActivityLayoutAreas(this MessageHub // Extract the owner ID from the hub address (e.g., "User/Alice" → "Alice") var nodeOwnerId = nodePath.StartsWith("User/") ? nodePath[5..] : nodePath; - // Get the node from the workspace stream to derive the owner's display name - var nodeStream = host.Workspace.GetStream()?.Select(nodes => nodes ?? Array.Empty()) - ?? Observable.Return(Array.Empty()); + var syncStream = host.Workspace.GetStream(new MeshNodeReference()); - return nodeStream.SelectMany(async nodes => + return syncStream!.Select(change => { - var ownerNode = nodes.FirstOrDefault(n => n.Path == nodePath); + var ownerNode = change.Value; var ownerName = ownerNode?.Name ?? nodeOwnerId; // Determine if the viewer is the node owner @@ -155,7 +153,8 @@ private static UiControl BuildVisitorProfile(string nodePath, string ownerName, .WithCollapsibleSections(false) .WithSectionCounts(false) .WithMaxColumns(4) - .WithItemLimit(8)); + .WithItemLimit(50) + .WithMaxRows(2)); // Visible child nodes — security service automatically filters to viewer-visible nodes content = content.WithView(Controls.MeshSearch @@ -164,7 +163,8 @@ private static UiControl BuildVisitorProfile(string nodePath, string ownerName, .WithShowEmptyMessage(true) .WithRenderMode(MeshSearchRenderMode.Grouped) .WithSectionCounts(true) - .WithItemLimit(20) + .WithItemLimit(50) + .WithMaxRows(3) .WithMaxColumns(4) .WithCollapsibleSections(true)); @@ -211,7 +211,8 @@ private static UiControl BuildActivityFeed() .WithCollapsibleSections(false) .WithSectionCounts(false) .WithMaxColumns(2) - .WithItemLimit(8)); + .WithItemLimit(50) + .WithMaxRows(4)); return section; } @@ -268,7 +269,8 @@ private static UiControl BuildRecentActivity(string nodePath) .WithCollapsibleSections(false) .WithSectionCounts(false) .WithMaxColumns(1) - .WithItemLimit(4); + .WithItemLimit(20) + .WithMaxRows(4); } /// @@ -279,11 +281,12 @@ private static UiControl BuildLatestThreads(string nodePath, string nodeOwnerId) { return Controls.MeshSearch .WithTitle("Latest Threads") - .WithHiddenQuery($"nodeType:Thread sort:LastModified-desc") + .WithHiddenQuery($"nodeType:Thread namespace:*/_Thread sort:LastModified-desc") .WithRenderMode(MeshSearchRenderMode.Flat) .WithCollapsibleSections(false) .WithSectionCounts(false) - .WithItemLimit(8) + .WithItemLimit(50) + .WithMaxRows(2) .WithMaxColumns(4) .WithCreateNodeType("Thread") .WithCreateNamespace(nodePath); @@ -301,7 +304,8 @@ private static UiControl BuildChildren(string nodePath) .WithRenderMode(MeshSearchRenderMode.Grouped) .WithSortBy("LastModified", ascending: false) .WithSectionCounts(true) - .WithItemLimit(10) + .WithItemLimit(50) + .WithMaxRows(3) .WithMaxColumns(4) .WithCollapsibleSections(true) .WithCreateHref($"/create?type=Markdown&namespace={Uri.EscapeDataString(nodePath)}"); diff --git a/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs b/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs index 6c924306e..3086c9b77 100644 --- a/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs +++ b/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs @@ -147,13 +147,22 @@ public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken ct) { try { - var accessService = _hub.ServiceProvider.GetRequiredService(); - using (accessService.ImpersonateAsHub(_hub)) + // Use IMeshQueryCore (no access control) — this is an infrastructure lookup + // during login, before the user's identity is established. + var queryCore = _hub.ServiceProvider.GetService(); + if (queryCore == null) + return null; + + var request = new MeshQueryRequest { - var meshService = _hub.ServiceProvider.GetRequiredService(); - return await meshService.QueryAsync( - $"nodeType:User namespace:User content.email:{email} limit:1").FirstOrDefaultAsync(); + Query = $"$type:MeshNode nodeType:User namespace:User content.email:{email} limit:1" + }; + await foreach (var item in queryCore.QueryAsync(request, _hub.JsonSerializerOptions)) + { + if (item is MeshNode node) + return node; } + return null; } catch (Exception ex) { diff --git a/src/MeshWeaver.Hosting.Orleans/AccessContextGrainCallFilter.cs b/src/MeshWeaver.Hosting.Orleans/AccessContextGrainCallFilter.cs index 451e95c38..addee3dac 100644 --- a/src/MeshWeaver.Hosting.Orleans/AccessContextGrainCallFilter.cs +++ b/src/MeshWeaver.Hosting.Orleans/AccessContextGrainCallFilter.cs @@ -13,19 +13,29 @@ public class AccessContextGrainCallFilter(ILogger { public async Task Invoke(IIncomingGrainCallContext context) { - var userId = RequestContext.Get("UserId") as string; - var userName = RequestContext.Get("UserName") as string; + try + { + var userId = RequestContext.Get("UserId") as string; + var userName = RequestContext.Get("UserName") as string; + + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug( + "GrainCallFilter: grain={Grain}, method={Method}, userId={UserId}, userName={UserName}", + context.TargetId, + context.MethodName, + userId ?? "(none)", + userName ?? "(none)"); + } - if (logger.IsEnabled(LogLevel.Debug)) + await context.Invoke(); + } + catch (NullReferenceException) when (context.MethodName is "Stop" or "Close") { - logger.LogDebug( - "GrainCallFilter: grain={Grain}, method={Method}, userId={UserId}, userName={UserName}", - context.TargetId, - context.MethodName, - userId ?? "(none)", - userName ?? "(none)"); + // Orleans internal streaming grains (PersistentStreamPullingManager) can throw + // NullReferenceException during shutdown. Swallow to prevent test/startup failures. + logger.LogDebug("GrainCallFilter: swallowed NullReferenceException in {Method} on {Grain}", + context.MethodName, context.TargetId); } - - await context.Invoke(); } } diff --git a/src/MeshWeaver.Hosting.Orleans/MessageHubGrain.cs b/src/MeshWeaver.Hosting.Orleans/MessageHubGrain.cs index 2cfcf1a47..1ea4d6994 100644 --- a/src/MeshWeaver.Hosting.Orleans/MessageHubGrain.cs +++ b/src/MeshWeaver.Hosting.Orleans/MessageHubGrain.cs @@ -10,6 +10,7 @@ namespace MeshWeaver.Hosting.Orleans; +[global::Orleans.Concurrency.Reentrant] public class MessageHubGrain(ILogger logger, IMessageHub meshHub) : Grain, IMessageHubGrain { @@ -25,30 +26,38 @@ public override async Task OnActivateAsync(CancellationToken cancellationToken) var address = meshHub.GetAddress(streamId); var addressPath = address.ToString(); - // Use unprotected read — the grain needs its own node to activate, - // and it's not the correct hub identity for security checks. - var node = await persistence.GetNodeAsync(addressPath, cancellationToken); - - // Fallback to MeshConfiguration.Nodes (in-memory registered nodes) - if (node is null) + // Resolve node from persistence, config, or static providers. + // Retry with backoff: the node may have just been created and persistence + // (debounce flush, cross-silo replication) may not have it yet. + MeshNode? node = null; + for (var attempt = 0; attempt < 5; attempt++) { - var meshConfig = meshHub.ServiceProvider.GetService(); - meshConfig?.Nodes.TryGetValue(addressPath, out node); - } + node = await persistence.GetNodeAsync(addressPath, cancellationToken); + + if (node is null) + { + var meshConfig = meshHub.ServiceProvider.GetService(); + meshConfig?.Nodes.TryGetValue(addressPath, out node); + } + + node ??= meshHub.ServiceProvider.GetServices() + .SelectMany(p => p.GetStaticNodes()) + .FirstOrDefault(n => string.Equals(n.Path, addressPath, StringComparison.OrdinalIgnoreCase)); - // Fallback to static node providers (e.g., DocumentationNodeProvider) - // for nodes that are never persisted but served as embedded resources. - node ??= meshHub.ServiceProvider.GetServices() - .SelectMany(p => p.GetStaticNodes()) - .FirstOrDefault(n => string.Equals(n.Path, addressPath, StringComparison.OrdinalIgnoreCase)); + if (node is not null) break; + + if (attempt < 4) + { + logger.LogDebug("Grain {StreamId}: node not found at {Path}, retry {Attempt}/4", + streamId, addressPath, attempt + 1); + await Task.Delay(200 * (attempt + 1), cancellationToken); + } + } if (node is null) { - // Throw so Orleans immediately rejects the message without forwarding attempts. - // Using DeactivateOnIdle() here would leave a zombie activation that triggers - // forwarding loops (ForwardCount=2 → OrleansMessageRejectionException). throw new InvalidOperationException( - $"Cannot activate grain {streamId}: node not found at {addressPath}."); + $"Cannot activate grain {streamId}: node not found at {addressPath} after 5 attempts."); } // Resolve hub configuration (triggers compilation if needed, composes with default config) @@ -62,7 +71,57 @@ public override async Task OnActivateAsync(CancellationToken cancellationToken) if (node.HubConfiguration is null) throw new ArgumentException($"No hub configuration resolved for {node.Path} (NodeType: {node.NodeType})."); - Hub = meshHub.GetHostedHub(address, node.HubConfiguration)!; + // Register a keep-alive timer that renews DelayDeactivation while + // long-running operations are active. The timer runs on the grain's scheduler. + // Operations increment/decrement the counter; timer only acts when > 0. + _keepAliveTimer = this.RegisterGrainTimer( + _ => + { + if (Volatile.Read(ref _activeOperations) > 0) + DelayDeactivation(TimeSpan.FromMinutes(10)); + return Task.CompletedTask; + }, + new GrainTimerCreationOptions + { + DueTime = TimeSpan.FromMinutes(1), + Period = TimeSpan.FromMinutes(1), + Interleave = true + }); + + Hub = meshHub.GetHostedHub(address, config => + node.HubConfiguration(config) + .Set(new GrainKeepAliveCallback(() => DelayDeactivation(TimeSpan.FromMinutes(10)))) + .Set(new GrainLongRunningOperationCallback(BeginLongRunningOperation)))!; + } + + private IGrainTimer? _keepAliveTimer; + private int _activeOperations; + + /// + /// Starts a long-running operation scope. + /// Increments the active operation counter and calls DelayDeactivation immediately. + /// The grain timer periodically renews while counter > 0. + /// Thread-safe: can be called from any thread (streaming loop, thread pool). + /// + private IDisposable BeginLongRunningOperation() + { + Interlocked.Increment(ref _activeOperations); + // DelayDeactivation is thread-safe in Orleans + DelayDeactivation(TimeSpan.FromMinutes(10)); + logger.LogInformation("Grain {GrainId}: long-running operation started (active={Count})", + this.GetPrimaryKeyString(), Volatile.Read(ref _activeOperations)); + + return new LongRunningOperationScope(() => + { + var remaining = Interlocked.Decrement(ref _activeOperations); + logger.LogInformation("Grain {GrainId}: long-running operation completed (active={Count})", + this.GetPrimaryKeyString(), remaining); + }); + } + + private sealed class LongRunningOperationScope(Action onDispose) : IDisposable + { + public void Dispose() => onDispose(); } @@ -106,7 +165,11 @@ public Task DeliverMessage(IMessageDelivery delivery) this.GetPrimaryKeyString(), msgType, userId ?? "(null)", deliveryUser ?? "(null)", delivery.AccessContext?.ObjectId ?? "(null)"); + logger.LogInformation("GrainDeliver: IN grain={Grain}, message={MessageType}, target={Target}, id={Id}", + this.GetPrimaryKeyString(), msgType, delivery.Target?.ToString() ?? "(self)", delivery.Id); var ret = Hub!.DeliverMessage(delivery); + logger.LogInformation("GrainDeliver: OUT grain={Grain}, message={MessageType}, state={State}, id={Id}", + this.GetPrimaryKeyString(), msgType, ret.State, delivery.Id); return Task.FromResult(ret); } @@ -120,12 +183,18 @@ public override async Task OnDeactivateAsync(DeactivationReason reason, Cancella { try { + // Cancel any active execution (e.g., AI streaming) — this triggers the + // OperationCanceledException path which saves state and notifies the parent. + Hub.CancelCurrentExecution(); + Hub.Dispose(); - // Wait for disposal (includes async flush of pending saves) + // Wait for disposal (includes async flush of pending saves and + // cancellation of active thread executions via hosted _Exec hubs). + // Allow up to 120s for AI streaming to cancel, save state, and flush. var disposalTask = Hub.Disposal!; - var completed = await Task.WhenAny(disposalTask, Task.Delay(TimeSpan.FromSeconds(10), cancellationToken)); + var completed = await Task.WhenAny(disposalTask, Task.Delay(TimeSpan.FromSeconds(120), cancellationToken)); if (completed != disposalTask) - logger.LogWarning("Grain {GrainId}: hub disposal timed out after 10s — pending saves may be lost!", grainId); + logger.LogWarning("Grain {GrainId}: hub disposal timed out after 120s — pending saves may be lost!", grainId); else logger.LogInformation("Grain {GrainId}: hub disposal completed", grainId); } diff --git a/src/MeshWeaver.Hosting.Orleans/OrleansMeshChangeFeed.cs b/src/MeshWeaver.Hosting.Orleans/OrleansMeshChangeFeed.cs new file mode 100644 index 000000000..dac28a751 --- /dev/null +++ b/src/MeshWeaver.Hosting.Orleans/OrleansMeshChangeFeed.cs @@ -0,0 +1,69 @@ +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Orleans.Streams; + +namespace MeshWeaver.Hosting.Orleans; + +/// +/// Orleans-distributed implementation of . +/// Wraps for local subscribers and +/// broadcasts to other silos via Orleans memory streams. +/// Stream publish runs through the hub's execution pipeline. +/// +public class OrleansMeshChangeFeed : IMeshChangeFeed +{ + private readonly InProcessMeshChangeFeed _local; + private readonly IMessageHub _hub; + private readonly ILogger? _logger; + + public OrleansMeshChangeFeed( + InProcessMeshChangeFeed localFeed, + IMessageHub hub, + ILogger? logger = null) + { + _local = localFeed; + _hub = hub; + _logger = logger; + } + + public void Publish(MeshChangeEvent change) + { + // Local subscribers get it immediately (synchronous) + _local.Publish(change); + + // Broadcast to other silos via Orleans stream + try + { + var client = _hub.ServiceProvider.GetService(); + if (client == null) return; + + var streamNs = $"mesh-{change.Kind.ToString().ToLowerInvariant()}"; + var streamProvider = client.GetStreamProvider(StreamProviders.Memory); + var stream = streamProvider.GetStream( + StreamId.Create(streamNs, Guid.Empty)); + + // Execute through hub's async pipeline with proper error handling + _hub.InvokeAsync(async _ => + { + await stream.OnNextAsync(change); + }, ex => + { + _logger?.LogError(ex, "Failed to broadcast MeshChangeEvent: {Path} {Kind}", + change.Path, change.Kind); + return Task.CompletedTask; + }); + } + catch (Exception ex) + { + // Stream provider not available (e.g., during shutdown) — local publish already happened + _logger?.LogDebug(ex, "Orleans stream broadcast skipped for {Path} {Kind}", + change.Path, change.Kind); + } + } + + public IDisposable Subscribe(Action handler, MeshChangeKind? filter = null) + => _local.Subscribe(handler, filter); +} diff --git a/src/MeshWeaver.Hosting.Orleans/OrleansServerRegistryExtensions.cs b/src/MeshWeaver.Hosting.Orleans/OrleansServerRegistryExtensions.cs index 6ee306619..7b99e9a22 100644 --- a/src/MeshWeaver.Hosting.Orleans/OrleansServerRegistryExtensions.cs +++ b/src/MeshWeaver.Hosting.Orleans/OrleansServerRegistryExtensions.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; namespace MeshWeaver.Hosting.Orleans; @@ -81,6 +82,15 @@ public static IServiceCollection AddOrleansMeshServices(this IServiceCollection // Register defaults if not already registered - user can register their own first services.AddInMemoryPersistence(); services.TryAddSingleton(); + + // Register Orleans-distributed change feed (wraps local feed + Orleans streams) + services.TryAddSingleton(); + services.TryAddSingleton(sp => + new OrleansMeshChangeFeed( + sp.GetRequiredService(), + sp.GetRequiredService(), + sp.GetService()?.CreateLogger())); + services.AddMeshCatalog(); return services; diff --git a/src/MeshWeaver.Hosting.Orleans/PathCacheInvalidatorGrain.cs b/src/MeshWeaver.Hosting.Orleans/PathCacheInvalidatorGrain.cs new file mode 100644 index 000000000..0367c73fe --- /dev/null +++ b/src/MeshWeaver.Hosting.Orleans/PathCacheInvalidatorGrain.cs @@ -0,0 +1,68 @@ +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using Microsoft.Extensions.Logging; +using Orleans.Streams; + +namespace MeshWeaver.Hosting.Orleans; + +/// +/// Grain that receives MeshChangeEvent broadcasts from other silos via Orleans streams +/// and relays them to the local . +/// +/// One instance per silo per stream namespace is activated implicitly. +/// Uses to avoid re-broadcasting. +/// +[ImplicitStreamSubscription("mesh-created")] +[ImplicitStreamSubscription("mesh-deleted")] +public class PathCacheInvalidatorGrain : Grain, IAsyncObserver +{ + private readonly InProcessMeshChangeFeed _localFeed; + private readonly ILogger? _logger; + + public PathCacheInvalidatorGrain( + InProcessMeshChangeFeed localFeed, + ILogger? logger = null) + { + _localFeed = localFeed; + _logger = logger; + } + + public override async Task OnActivateAsync(CancellationToken cancellationToken) + { + var streamProvider = this.GetStreamProvider(StreamProviders.Memory); + + // Subscribe to all stream namespaces this grain is implicitly subscribed to + foreach (var ns in new[] { "mesh-created", "mesh-deleted" }) + { + var stream = streamProvider.GetStream( + StreamId.Create(ns, this.GetPrimaryKey())); + + // Check for existing subscriptions (resume after reactivation) + var handles = await stream.GetAllSubscriptionHandles(); + if (handles is { Count: > 0 }) + { + foreach (var handle in handles) + await handle.ResumeAsync(this); + } + else + { + await stream.SubscribeAsync(this); + } + } + } + + public Task OnNextAsync(MeshChangeEvent item, StreamSequenceToken? token = null) + { + _logger?.LogDebug("PathCacheInvalidatorGrain: received {Kind} {Path} from stream", item.Kind, item.Path); + _localFeed.PublishLocal(item); + return Task.CompletedTask; + } + + public Task OnCompletedAsync() => Task.CompletedTask; + + public Task OnErrorAsync(Exception ex) + { + _logger?.LogWarning(ex, "PathCacheInvalidatorGrain: stream error"); + return Task.CompletedTask; + } +} diff --git a/src/MeshWeaver.Hosting.Orleans/RoutingGrain.cs b/src/MeshWeaver.Hosting.Orleans/RoutingGrain.cs index e998d7ef1..308a59149 100644 --- a/src/MeshWeaver.Hosting.Orleans/RoutingGrain.cs +++ b/src/MeshWeaver.Hosting.Orleans/RoutingGrain.cs @@ -16,24 +16,49 @@ internal class RoutingGrain( public async Task RouteMessage(IMessageDelivery delivery) { var address = GetHostAddress(delivery.Target!); + var addressPath = address.ToString(); + var resolution = await pathResolver.ResolvePathAsync(addressPath); + var grainKey = resolution?.Prefix ?? addressPath; - var resolution = await pathResolver.ResolvePathAsync(address.ToString()); - var grainKey = resolution?.Prefix; + logger.LogDebug("RouteMessage: {MessageType} → address={Address}, resolved={Prefix}, remainder={Remainder}, grainKey={GrainKey}", + delivery.Message.GetType().Name, addressPath, resolution?.Prefix ?? "(null)", + resolution?.Remainder ?? "(null)", grainKey); - var targetKey = grainKey ?? address.ToString(); + // When resolution splits the path into prefix + remainder, update the delivery + // to match the resolved grain address. Without this, the grain receives a delivery + // whose Target doesn't match its hub address → routing loop. + if (resolution != null && !string.IsNullOrEmpty(resolution.Remainder)) + { + logger.LogInformation("RouteMessage: updating target for {MessageType}: {Original} → prefix={Prefix}, remainder={Remainder}", + delivery.Message.GetType().Name, addressPath, resolution.Prefix, resolution.Remainder); + var resolvedAddress = new Address(resolution.Prefix.Split('/')); + delivery = delivery.WithProperty("UnifiedPath", resolution.Remainder); + delivery = delivery.WithTarget(resolvedAddress); + } + + // Portal/client hubs are not grains — deliver via Orleans memory stream. + // The portal subscribes to this stream in OrleansRoutingService.RegisterStreamAsync. + if (address.Type == AddressExtensions.PortalType || address.Type == "client") + { + logger.LogDebug("RouteMessage: delivering to {Address} via memory stream (not a grain)", addressPath); + var stream = this.GetStreamProvider(StreamProviders.Memory) + .GetStream(addressPath); + await stream.OnNextAsync(delivery); + return delivery.Forwarded(address); + } try { - var grain = GrainFactory.GetGrain(targetKey); + var grain = GrainFactory.GetGrain(grainKey); return await grain.DeliverMessage(delivery); } catch (Exception ex) { - logger.LogDebug(ex, "Grain delivery failed for {Address} (key={Key}), falling back to stream", - address, targetKey); + logger.LogWarning(ex, "Grain delivery failed for {MessageType} to {Address} (key={Key}), falling back to stream", + delivery.Message.GetType().Name, address, grainKey); var stream = this.GetStreamProvider(StreamProviders.Memory) - .GetStream(address.ToString()); + .GetStream(addressPath); await stream.OnNextAsync(delivery); return delivery.Forwarded(address); } diff --git a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlCrossSchemaQueryProvider.cs b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlCrossSchemaQueryProvider.cs index e2871ec1d..54bd134e6 100644 --- a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlCrossSchemaQueryProvider.cs +++ b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlCrossSchemaQueryProvider.cs @@ -204,6 +204,33 @@ private static MeshNode ReadMeshNode(NpgsqlDataReader reader, JsonSerializerOpti }; } + public async IAsyncEnumerable QueryAcrossSchemasAsync( + ParsedQuery query, + JsonSerializerOptions options, + IReadOnlyList schemas, + string tableName, + string? userId = null, + [EnumeratorCancellation] CancellationToken ct = default) + { + if (schemas.Count == 0) + yield break; + + var generator = new PostgreSqlSqlGenerator(); + var (sql, parameters) = generator.GenerateCrossSchemaSelectQuery(query, schemas, userId, tableName); + + _logger?.LogInformation( + "[CrossSchema] Satellite query: table={Table}, schemas={Count}, userId={User}", + tableName, schemas.Count, userId); + + await using var cmd = _dataSource.CreateCommand(sql); + foreach (var (name, value) in parameters) + cmd.Parameters.Add(new NpgsqlParameter(name, value ?? DBNull.Value)); + + await using var reader = await cmd.ExecuteReaderAsync(ct); + while (await reader.ReadAsync(ct)) + yield return ReadMeshNode(reader, options); + } + private static string EscapeSql(string input) => input.Replace("'", "''"); } diff --git a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlMeshQuery.cs b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlMeshQuery.cs index 99685bbbd..35f6a495a 100644 --- a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlMeshQuery.cs +++ b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlMeshQuery.cs @@ -49,6 +49,10 @@ public PostgreSqlMeshQuery( /// private string GetEffectiveUserId(MeshQueryRequest request) { + // System identity bypasses access control (infrastructure queries) + if (request.UserId == WellKnownUsers.System) + return ""; + if (!string.IsNullOrEmpty(request.UserId)) return request.UserId; diff --git a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSqlGenerator.cs b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSqlGenerator.cs index a96c5dfd4..a0ac51ad5 100644 --- a/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSqlGenerator.cs +++ b/src/MeshWeaver.Hosting.PostgreSql/PostgreSqlSqlGenerator.cs @@ -262,7 +262,10 @@ private static string MapOrderBySelector(string selector) string? userId = null, string tableName = "mesh_nodes") { - var (whereClause, parameters) = GenerateWhereClause(query, userId); + // Don't pass userId to GenerateWhereClause — access control is handled per-schema + // by BuildPerSchemaAccessClause with properly schema-qualified table names. + // GenerateWhereClause would add unqualified UEP references that resolve to public schema. + var (whereClause, parameters) = GenerateWhereClause(query); var parts = new List(); foreach (var schema in schemas) @@ -290,7 +293,9 @@ private static string MapOrderBySelector(string selector) if (query.OrderBy != null) { var direction = query.OrderBy.Descending ? "DESC" : "ASC"; - sql = $"SELECT * FROM ({sql}) combined ORDER BY {MapOrderBySelector(query.OrderBy.Property)} {direction}"; + // Strip "n." prefix — the outer query uses alias "combined", not "n" + var orderCol = MapOrderBySelector(query.OrderBy.Property).Replace("n.", ""); + sql = $"SELECT * FROM ({sql}) combined ORDER BY {orderCol} {direction}"; } if (query.Limit.HasValue) @@ -666,16 +671,17 @@ private string GenerateAccessControlClause(string userId) ? $"EXISTS (SELECT 1 FROM public.partition_access pa WHERE pa.user_id IN ({userList}) AND pa.partition = '{SchemaName}')" : ""; - // Public-read node types (e.g. User, Organization) are visible to all authenticated users - // regardless of partition_access. + // Public-read node types (e.g. User, Markdown) are visible to all authenticated users + // who have partition access. public_read skips node-level permission checks but + // still requires partition_access — prevents cross-partition data leakage. var publicReadClause = userId == WellKnownUsers.Anonymous ? "" : $"EXISTS (SELECT 1 FROM {ntpTable} ntp WHERE ntp.node_type = n.node_type AND ntp.public_read = true)"; // Build the access control clause: - // A node is visible if: - // (a) public-read node type (bypasses partition check), OR - // (b) user has partition access AND (owns the node OR has Read permission) + // A node is visible if the user has partition access (when schema-qualified) AND: + // (a) public-read node type (no further permission check), OR + // (b) owns the node OR has Read permission var nodeAccessClause = $""" n.main_node = {paramName} OR @@ -689,21 +695,19 @@ ORDER BY LENGTH(uep.node_path_prefix) DESC, LIMIT 1) = true """; - if (!string.IsNullOrEmpty(publicReadClause) && hasPartitionCheck) - { - // Schema-qualified + authenticated: public-read OR (partition_access AND node-level) - return $""" - ( - {publicReadClause} - OR - ({partitionAccessExists} AND ({nodeAccessClause})) - ) - """; - } - if (hasPartitionCheck) { - // Schema-qualified + anonymous: partition_access AND node-level + // Schema-qualified: partition_access is always required. + // public_read skips node-level checks but NOT partition access. + if (!string.IsNullOrEmpty(publicReadClause)) + { + return $""" + ( + {partitionAccessExists} AND ({publicReadClause} OR {nodeAccessClause}) + ) + """; + } + return $""" ( {partitionAccessExists} AND ({nodeAccessClause}) @@ -711,7 +715,7 @@ ORDER BY LENGTH(uep.node_path_prefix) DESC, """; } - // No schema: just node-level access + // No schema: just node-level access (or public-read bypass) if (!string.IsNullOrEmpty(publicReadClause)) { return $""" diff --git a/src/MeshWeaver.Hosting/MeshCatalog.cs b/src/MeshWeaver.Hosting/MeshCatalog.cs index 8a68e8d84..57c2fdbf9 100644 --- a/src/MeshWeaver.Hosting/MeshCatalog.cs +++ b/src/MeshWeaver.Hosting/MeshCatalog.cs @@ -243,32 +243,45 @@ private static bool ValidatePath(MeshNode node) private static readonly MemoryCacheEntryOptions ResolveCacheOptions = new() { SlidingExpiration = TimeSpan.FromMinutes(5) }; + /// + /// Invalidates path resolution cache entries affected by a node change. + /// Called after node create/delete to ensure routing uses fresh data. + /// Invalidates the exact path AND all ancestor paths (which may have + /// cached partial matches with remainder pointing to the changed node). + /// + public void InvalidatePathCache(string path) + { + if (string.IsNullOrEmpty(path)) return; + path = path.TrimStart('/'); + + // Invalidate exact path + cache.Remove($"resolve:{path}"); + + // Invalidate all ancestor paths — they may have cached partial matches + var segments = path.Split('/'); + for (var i = segments.Length - 1; i >= 1; i--) + { + var ancestorPath = string.Join("/", segments.Take(i)); + cache.Remove($"resolve:{ancestorPath}"); + } + } + /// + /// + /// Resolves a path. Prefer using IPathResolver (PathResolutionService) which adds caching. + /// This method is a direct passthrough to ResolvePathCoreAsync. + /// public async Task ResolvePathAsync(string path) { if (string.IsNullOrEmpty(path)) return null; - - // Normalize path - remove leading slash if present path = path.TrimStart('/'); if (string.IsNullOrEmpty(path)) return null; - - // Check resolution cache first - var cacheKey = $"resolve:{path}"; - if (cache.TryGetValue(cacheKey, out var cachedResolution) && cachedResolution is AddressResolution cached) - return cached; - - var resolution = await ResolvePathCoreAsync(path); - - // Cache the result (including null → cache as sentinel) - if (resolution != null) - cache.Set(cacheKey, resolution, ResolveCacheOptions); - - return resolution; + return await ResolvePathCoreAsync(path); } - private async Task ResolvePathCoreAsync(string path) + internal async Task ResolvePathCoreAsync(string path) { var segments = path.Split('/'); diff --git a/src/MeshWeaver.Hosting/MeshChangeFeed.cs b/src/MeshWeaver.Hosting/MeshChangeFeed.cs new file mode 100644 index 000000000..46347456b --- /dev/null +++ b/src/MeshWeaver.Hosting/MeshChangeFeed.cs @@ -0,0 +1,54 @@ +using System.Reactive.Subjects; +using MeshWeaver.Mesh.Services; + +namespace MeshWeaver.Hosting; + +/// +/// In-process implementation of . +/// Uses Rx Subject for local pub/sub. Suitable for monolith mode. +/// In Orleans, OrleansMeshChangeFeed wraps this and adds +/// BroadcastChannel for cross-silo propagation. +/// +public class InProcessMeshChangeFeed : IMeshChangeFeed, IDisposable +{ + private readonly Subject _subject = new(); + private bool _disposed; + + public void Publish(MeshChangeEvent change) + { + if (!_disposed) + _subject.OnNext(change); + } + + /// + /// Publishes locally without re-broadcasting to Orleans streams. + /// Used by PathCacheInvalidatorGrain to relay cross-silo events + /// to local subscribers without creating an infinite loop. + /// + public void PublishLocal(MeshChangeEvent change) + { + if (!_disposed) + _subject.OnNext(change); + } + + public IDisposable Subscribe(Action handler, MeshChangeKind? filter = null) + { + if (filter == null) + return _subject.Subscribe(handler); + + var kind = filter.Value; + return _subject.Subscribe(e => + { + if (e.Kind == kind) + handler(e); + }); + } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + _subject.OnCompleted(); + _subject.Dispose(); + } +} diff --git a/src/MeshWeaver.Hosting/PathResolutionService.cs b/src/MeshWeaver.Hosting/PathResolutionService.cs new file mode 100644 index 000000000..974eb5055 --- /dev/null +++ b/src/MeshWeaver.Hosting/PathResolutionService.cs @@ -0,0 +1,113 @@ +using System.Collections.Concurrent; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; + +namespace MeshWeaver.Hosting; + +/// +/// Resolves URL paths to hub addresses with an internally managed cache. +/// Subscribes to to invalidate cache entries +/// on create/delete — this is an implementation detail, not exposed in the API. +/// +/// In Orleans: register as singleton on each silo. Each silo maintains its own cache. +/// Cross-silo invalidation happens via Orleans streams → local IMeshChangeFeed. +/// +internal class PathResolutionService : IPathResolver, IDisposable +{ + private readonly MeshCatalog _catalog; + private readonly IMemoryCache _cache = new MemoryCache(new MemoryCacheOptions()); + private readonly ConcurrentDictionary _pathTokens = new(); + private readonly IDisposable? _createSub; + private readonly IDisposable? _deleteSub; + private readonly ILogger? _logger; + + public PathResolutionService( + MeshCatalog catalog, + IMeshChangeFeed? changeFeed = null, + ILogger? logger = null) + { + _catalog = catalog; + _logger = logger; + + // Subscribe internally — cache invalidation is our concern, nobody else's + _createSub = changeFeed?.Subscribe(OnCreated, MeshChangeKind.Created); + _deleteSub = changeFeed?.Subscribe(OnDeleted, MeshChangeKind.Deleted); + } + + public async Task ResolvePathAsync(string path) + { + if (string.IsNullOrEmpty(path)) + return null; + + path = path.TrimStart('/'); + if (string.IsNullOrEmpty(path)) + return null; + + var cacheKey = $"resolve:{path}"; + if (_cache.TryGetValue(cacheKey, out var cached) && cached is AddressResolution resolution) + return resolution; + + // Delegate the actual resolution to MeshCatalog (DB lookups, config matching) + var result = await _catalog.ResolvePathCoreAsync(path); + + if (result != null) + CacheResolution(path, result); + + return result; + } + + private void OnCreated(MeshChangeEvent e) + { + var path = e.Path.TrimStart('/'); + _logger?.LogDebug("PathResolution cache: Created {Path}", path); + InvalidateSubtree(path); + CacheResolution(path, new AddressResolution(path, null)); + } + + private void OnDeleted(MeshChangeEvent e) + { + var path = e.Path.TrimStart('/'); + _logger?.LogDebug("PathResolution cache: Deleted {Path}", path); + InvalidateSubtree(path); + } + + private void InvalidateSubtree(string path) + { + foreach (var key in _pathTokens.Keys) + { + if (key.Equals(path, StringComparison.OrdinalIgnoreCase) + || key.StartsWith(path + "/", StringComparison.OrdinalIgnoreCase)) + { + if (_pathTokens.TryRemove(key, out var cts)) + { + cts.Cancel(); + cts.Dispose(); + } + } + } + } + + private void CacheResolution(string path, AddressResolution resolution) + { + var cts = _pathTokens.GetOrAdd(path, _ => new CancellationTokenSource()); + var options = new MemoryCacheEntryOptions() + .SetSlidingExpiration(TimeSpan.FromMinutes(5)) + .AddExpirationToken(new CancellationChangeToken(cts.Token)); + _cache.Set($"resolve:{path}", resolution, options); + } + + public void Dispose() + { + _createSub?.Dispose(); + _deleteSub?.Dispose(); + _cache.Dispose(); + foreach (var cts in _pathTokens.Values) + { + cts.Cancel(); + cts.Dispose(); + } + } +} diff --git a/src/MeshWeaver.Hosting/Persistence/PersistenceExtensions.cs b/src/MeshWeaver.Hosting/Persistence/PersistenceExtensions.cs index 0133b896b..0b10d1045 100644 --- a/src/MeshWeaver.Hosting/Persistence/PersistenceExtensions.cs +++ b/src/MeshWeaver.Hosting/Persistence/PersistenceExtensions.cs @@ -495,9 +495,12 @@ private static IServiceCollection AddCoreAndWrapperServices(th ///
public static IServiceCollection AddMeshCatalog(this IServiceCollection services) { + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(sp => sp.GetRequiredService()); - services.TryAddSingleton(sp => sp.GetRequiredService()); + // PathResolutionService owns the cache + subscribes to IMeshChangeFeed internally + services.TryAddSingleton(); + services.TryAddSingleton(sp => sp.GetRequiredService()); return services; } } diff --git a/src/MeshWeaver.Hosting/Persistence/PersistenceService.cs b/src/MeshWeaver.Hosting/Persistence/PersistenceService.cs index 5adcc0a19..76f6d1bc5 100644 --- a/src/MeshWeaver.Hosting/Persistence/PersistenceService.cs +++ b/src/MeshWeaver.Hosting/Persistence/PersistenceService.cs @@ -144,7 +144,7 @@ private async Task HasReadAccessAsync(MeshNode node, string? userId, Cance if (await HasReadAccessAsync(node, userId, ct)) return node; - logger?.LogDebug("SecurePersistence: User {UserId} denied read access to {Path}", userId ?? "(anonymous)", path); + logger?.LogWarning("SecurePersistence: User {UserId} denied read access to {Path}", userId ?? "(anonymous)", path); return null; } diff --git a/src/MeshWeaver.Hosting/Persistence/Query/RoutingMeshQueryProvider.cs b/src/MeshWeaver.Hosting/Persistence/Query/RoutingMeshQueryProvider.cs index d8aee8f78..6015e02e0 100644 --- a/src/MeshWeaver.Hosting/Persistence/Query/RoutingMeshQueryProvider.cs +++ b/src/MeshWeaver.Hosting/Persistence/Query/RoutingMeshQueryProvider.cs @@ -102,26 +102,33 @@ public async IAsyncEnumerable QueryAsync( fanOutQuery += " is:main"; // Cross-schema query: single UNION ALL across all searchable schemas (PostgreSQL only). - // Only for queries on mesh_nodes — satellite queries (source:activity, source:accessed) - // and satellite node types (Thread, ThreadMessage) require per-partition fan-out - // because the stored proc only searches mesh_nodes. + // Works for both mesh_nodes and satellite tables (threads, activities, etc.). var satelliteNodeType = parsed.ExtractNodeType() is { } nt && PartitionDefinition.NodeTypeToSuffix.ContainsKey(nt); var useCrossSchema = _crossSchemaProvider != null - && parsed.Source == QuerySource.Default - && !satelliteNodeType; + && parsed.Source == QuerySource.Default; if (useCrossSchema) { var schemas = await _crossSchemaProvider!.GetSearchableSchemasAsync(ct); var crossParsed = _parser.Parse(fanOutQuery); var userId = GetEffectiveUserId(); - _logger?.LogDebug("Cross-schema query: {Query}, schemas=[{Schemas}], userId={UserId}", - fanOutQuery, string.Join(",", schemas), userId); + // Resolve satellite table name if applicable + string? satelliteTable = null; + if (satelliteNodeType && parsed.ExtractNodeType() is { } nodeType) + { + var suffix = PartitionDefinition.NodeTypeToSuffix[nodeType]; + PartitionDefinition.StandardTableMappings.TryGetValue(suffix, out satelliteTable); + } + + _logger?.LogDebug("Cross-schema query: {Query}, table={Table}, schemas=[{Schemas}], userId={UserId}", + fanOutQuery, satelliteTable ?? "mesh_nodes", string.Join(",", schemas), userId); var crossResults = new List(); - await foreach (var node in _crossSchemaProvider.QueryAcrossSchemasAsync( - crossParsed, options, schemas, userId, ct)) + var crossStream = satelliteTable != null + ? _crossSchemaProvider.QueryAcrossSchemasAsync(crossParsed, options, schemas, satelliteTable, userId, ct) + : _crossSchemaProvider.QueryAcrossSchemasAsync(crossParsed, options, schemas, userId, ct); + await foreach (var node in crossStream) { crossResults.Add(node); } diff --git a/src/MeshWeaver.Hosting/Security/SecurePersistenceServiceDecorator.cs b/src/MeshWeaver.Hosting/Security/SecurePersistenceServiceDecorator.cs index d13f86adf..905d015c4 100644 --- a/src/MeshWeaver.Hosting/Security/SecurePersistenceServiceDecorator.cs +++ b/src/MeshWeaver.Hosting/Security/SecurePersistenceServiceDecorator.cs @@ -79,7 +79,7 @@ private async Task HasReadAccessAsync(MeshNode node, string? userId, Cance if (await HasReadAccessAsync(node, userId, ct)) return node; - _logger.LogDebug("SecurePersistence: User {UserId} denied read access to {Path}", userId ?? "(anonymous)", path); + _logger.LogWarning("SecurePersistence: User {UserId} denied read access to {Path}", userId ?? "(anonymous)", path); return null; } diff --git a/src/MeshWeaver.Hosting/Security/SecurityService.cs b/src/MeshWeaver.Hosting/Security/SecurityService.cs index 4234ea24f..d8a5b102d 100644 --- a/src/MeshWeaver.Hosting/Security/SecurityService.cs +++ b/src/MeshWeaver.Hosting/Security/SecurityService.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.Collections.Immutable; using System.Runtime.CompilerServices; using System.Text.Json; using MeshWeaver.Mesh; @@ -137,6 +138,10 @@ public async Task GetEffectivePermissionsAsync(string nodePath, stri if (string.IsNullOrEmpty(userId)) userId = WellKnownUsers.Anonymous; + // System identity has full access — used by SecurityService for internal operations + if (userId == WellKnownUsers.System) + return Permission.All; + var cacheKey = $"{userId}:{nodePath}"; if (_permissionCache.TryGetValue(cacheKey, out Permission cached)) return cached; @@ -487,11 +492,11 @@ public async Task AddUserRoleAsync(string userId, string roleId, string? targetN } var existingAssignment = existingNode != null ? DeserializeAssignment(existingNode) : null; - var roles = existingAssignment?.Roles?.ToList() ?? []; + var roles = existingAssignment?.Roles?.ToImmutableList() ?? ImmutableList.Empty; // Add role if not already present if (!roles.Any(r => r.Role == roleId)) - roles.Add(new RoleAssignment { Role = roleId }); + roles = roles.Add(new RoleAssignment { Role = roleId }); var node = new MeshNode(nodeId, ns) { @@ -539,7 +544,7 @@ public async Task RemoveUserRoleAsync(string userId, string roleId, string? targ if (existingAssignment == null) return; // Nothing to remove - var roles = existingAssignment.Roles.Where(r => r.Role != roleId).ToList(); + var roles = existingAssignment.Roles.Where(r => r.Role != roleId).ToImmutableList(); if (roles.Count == 0) { @@ -609,6 +614,7 @@ public async Task SetPolicyAsync(string targetNamespace, PartitionAccessPolicy p }; await _persistenceCore.SaveNodeAsync(node, Options, ct); + _policyCache[ns] = policy; ClearPermissionCache(); } diff --git a/src/MeshWeaver.Layout/Catalog/CatalogTypes.cs b/src/MeshWeaver.Layout/Catalog/CatalogTypes.cs index 30322fecf..281233d09 100644 --- a/src/MeshWeaver.Layout/Catalog/CatalogTypes.cs +++ b/src/MeshWeaver.Layout/Catalog/CatalogTypes.cs @@ -34,6 +34,13 @@ public record SectionConfig /// public int? ItemLimit { get; init; } + /// + /// Maximum number of visible grid rows per section. + /// Items beyond this are hidden via CSS overflow; a "Show all" toggle reveals them. + /// Null means no row limit (all loaded items are visible). + /// + public int? MaxRows { get; init; } + /// /// Whether sections can be collapsed/expanded (default true). /// diff --git a/src/MeshWeaver.Layout/Client/LayoutClientExtensions.cs b/src/MeshWeaver.Layout/Client/LayoutClientExtensions.cs index cd4e7b9a5..9a97465fe 100644 --- a/src/MeshWeaver.Layout/Client/LayoutClientExtensions.cs +++ b/src/MeshWeaver.Layout/Client/LayoutClientExtensions.cs @@ -330,18 +330,37 @@ private static T ConvertString(string s) { if (value == null) return default; - if (conversion != null) - return conversion(JsonSerializer.Deserialize(value.Value.GetRawText(), hub.JsonSerializerOptions), defaultValue); - return JsonSerializer.Deserialize(value.Value.GetRawText(), hub.JsonSerializerOptions); + try + { + if (conversion != null) + return conversion(JsonSerializer.Deserialize(value.Value.GetRawText(), hub.JsonSerializerOptions), defaultValue); + return JsonSerializer.Deserialize(value.Value.GetRawText(), hub.JsonSerializerOptions); + } + catch (JsonException ex) + { + hub.ServiceProvider.GetService()?.CreateLogger("MeshWeaver.Layout.ConvertJson") + .LogError(ex, "ConvertJson<{Type}> failed for JsonElement {ValueKind}: {Raw}", + typeof(T).Name, value.Value.ValueKind, value.Value.GetRawText()[..Math.Min(100, value.Value.GetRawText().Length)]); + return defaultValue; + } } private static T? ConvertJson(this IMessageHub hub, JsonObject? value, Func? conversion, T? defaultValue) { if (value == null) return default; - if (conversion != null) - return conversion(value.Deserialize(hub.JsonSerializerOptions), defaultValue); - return value.Deserialize(hub.JsonSerializerOptions); + try + { + if (conversion != null) + return conversion(value.Deserialize(hub.JsonSerializerOptions), defaultValue); + return value.Deserialize(hub.JsonSerializerOptions); + } + catch (JsonException ex) + { + hub.ServiceProvider.GetService()?.CreateLogger("MeshWeaver.Layout.ConvertJson") + .LogError(ex, "ConvertJson<{Type}> failed for JsonObject", typeof(T).Name); + return defaultValue; + } } public static async Task SubmitModel(this ISynchronizationStream stream, ModelParameter data) { diff --git a/src/MeshWeaver.Layout/MeshSearchControl.cs b/src/MeshWeaver.Layout/MeshSearchControl.cs index bcd67da5e..2d362abff 100644 --- a/src/MeshWeaver.Layout/MeshSearchControl.cs +++ b/src/MeshWeaver.Layout/MeshSearchControl.cs @@ -192,6 +192,9 @@ public MeshSearchControl WithSectionCounts(bool showCounts) => public MeshSearchControl WithItemLimit(int limit) => this with { Sections = (Sections ?? new SectionConfig()) with { ItemLimit = limit } }; + public MeshSearchControl WithMaxRows(int rows) => + this with { Sections = (Sections ?? new SectionConfig()) with { MaxRows = rows } }; + public MeshSearchControl WithCollapsibleSections(bool collapsible) => this with { Sections = (Sections ?? new SectionConfig()) with { Collapsible = collapsible } }; diff --git a/src/MeshWeaver.Layout/ThreadMessageActionRequests.cs b/src/MeshWeaver.Layout/ThreadMessageActionRequests.cs new file mode 100644 index 000000000..241b5b80c --- /dev/null +++ b/src/MeshWeaver.Layout/ThreadMessageActionRequests.cs @@ -0,0 +1,25 @@ +namespace MeshWeaver.Layout; + +/// +/// Request to resubmit a user message in a thread. +/// The handler truncates ThreadMessages from the given message onwards, +/// then posts a new SubmitMessageRequest with the provided text. +/// +public record ResubmitMessageRequest +{ + public required string ThreadPath { get; init; } + public required string MessageId { get; init; } + public required string UserMessageText { get; init; } + /// Client-generated output cell ID. If set, server skips cell creation. + public string? OutputMessageId { get; init; } +} + +/// +/// Request to delete a message and all subsequent messages from a thread. +/// The handler truncates ThreadMessages from the given message onwards. +/// +public record DeleteFromMessageRequest +{ + public required string ThreadPath { get; init; } + public required string MessageId { get; init; } +} diff --git a/src/MeshWeaver.Layout/ThreadMessageBubbleControl.cs b/src/MeshWeaver.Layout/ThreadMessageBubbleControl.cs index 9e401659b..173145f9f 100644 --- a/src/MeshWeaver.Layout/ThreadMessageBubbleControl.cs +++ b/src/MeshWeaver.Layout/ThreadMessageBubbleControl.cs @@ -41,6 +41,11 @@ public record ThreadMessageBubbleControl() : UiControl public string? ThreadPath { get; init; } + /// + /// The message ID within the thread. Used for edit/resubmit/delete operations. + /// + public string? MessageId { get; init; } + /// /// Data-bound list of completed tool calls for post-execution inspection. /// Rendered as collapsible entries in the Blazor view. @@ -60,6 +65,7 @@ public record ThreadMessageBubbleControl() : UiControl this with { Text = text }; public ThreadMessageBubbleControl WithIsExecuting(object? isExecuting) => this with { IsExecuting = isExecuting }; public ThreadMessageBubbleControl WithExecutionStatus(object? status) => this with { ExecutionStatus = status }; + public ThreadMessageBubbleControl WithMessageId(string? id) => this with { MessageId = id }; public ThreadMessageBubbleControl WithThreadPath(string? path) => this with { ThreadPath = path }; public ThreadMessageBubbleControl WithToolCalls(object? toolCalls) => this with { ToolCalls = toolCalls }; } diff --git a/src/MeshWeaver.Mesh.Contract/CreateNodeRequest.cs b/src/MeshWeaver.Mesh.Contract/CreateNodeRequest.cs index 377da1ef5..9a3bcf908 100644 --- a/src/MeshWeaver.Mesh.Contract/CreateNodeRequest.cs +++ b/src/MeshWeaver.Mesh.Contract/CreateNodeRequest.cs @@ -354,6 +354,7 @@ public static Permission GetPermissionForNodeType(string? nodeType) { "Thread" or "ThreadMessage" => Permission.Thread, "Comment" => Permission.Comment, + "ApiToken" => Permission.Api, _ => Permission.Create }; diff --git a/src/MeshWeaver.Mesh.Contract/MeshExtensions.cs b/src/MeshWeaver.Mesh.Contract/MeshExtensions.cs index 23a201560..1908fa753 100644 --- a/src/MeshWeaver.Mesh.Contract/MeshExtensions.cs +++ b/src/MeshWeaver.Mesh.Contract/MeshExtensions.cs @@ -59,7 +59,36 @@ public static MessageHubConfiguration WithNodeOperationHandlers(this MessageHubC .WithHandler(HandleCreateNodeRequest) .WithHandler(HandleDeleteNodeRequest) .WithHandler(HandleUpdateNodeRequest) - .WithHandler(HandleMoveNodeRequest); + .WithHandler(HandleMoveNodeRequest) + .WithHandler(HandleHeartBeat); + } + + /// + /// Handles HeartBeatEvent: signals the Orleans grain to delay deactivation. + /// Walks up the parent hub chain because GrainKeepAliveCallback is set on the + /// grain's top-level hub, not on child hubs (threads, messages, _Exec). + /// In monolith mode, no GrainKeepAliveCallback is registered → no-op. + /// + private static IMessageDelivery HandleHeartBeat( + IMessageHub hub, IMessageDelivery delivery) + { + var current = hub; + while (current != null) + { + var callback = current.Configuration.Get(); + if (callback != null) + { + var logger = hub.ServiceProvider.GetService()?.CreateLogger("MeshWeaver.GrainKeepAlive"); + logger?.LogInformation("HeartBeat: keeping grain alive for {Hub} (callback on {Parent})", + hub.Address, current.Address); + callback.KeepAlive(); + break; + } + var parent = current.Configuration.ParentHub; + if (parent == current) break; + current = parent; + } + return delivery.Processed(); } private static async Task HandleCreateNodeRequest( @@ -206,6 +235,11 @@ private static async Task HandleCreateNodeRequest( newNode = await persistence.SaveNodeAsync(newNode, ct); } + // 6a. Notify infrastructure of the new node (cache invalidation, query updates) + hub.ServiceProvider.GetService() + ?.Publish(MeshChangeEvent.Created(newNode)); + + // 7. Write version history snapshot (non-critical, skip satellite types like threads/comments) if (!catalog.Configuration.IsSatelliteNodeType(newNode.NodeType)) { @@ -308,6 +342,8 @@ private static async Task HandleDeleteNodeRequest( { // Leaf node — delete immediately await catalog.DeleteNodeAsync(path, recursive: false, ct); + hub.ServiceProvider.GetService() + ?.Publish(MeshChangeEvent.Deleted(path)); hub.Post(DeleteNodeResponse.Ok(), o => o.ResponseFor(request)); logger.LogInformation("Node deleted at {Path} by {DeletedBy}", path, deleteRequest.DeletedBy ?? "system"); return request.Processed(); @@ -624,6 +660,8 @@ private static async Task HandleUpdateNodeRequest( // 5. Persist the validated node var persistence = hub.ServiceProvider.GetRequiredService(); var savedNode = await persistence.SaveNodeAsync(nodeToSave, ct); + hub.ServiceProvider.GetService() + ?.Publish(MeshChangeEvent.Updated(savedNode)); // 5b. Write version history snapshot (non-critical, skip satellite types like threads/comments) if (!catalog.Configuration.IsSatelliteNodeType(savedNode.NodeType)) @@ -777,6 +815,9 @@ private static async Task HandleMoveNodeRequest( // 4. Move the node var movedNode = await persistence.MoveNodeAsync(moveRequest.SourcePath, moveRequest.TargetPath, ct); + var changeFeed = hub.ServiceProvider.GetService(); + changeFeed?.Publish(MeshChangeEvent.Deleted(moveRequest.SourcePath)); + changeFeed?.Publish(MeshChangeEvent.Created(movedNode)); // 5. Return success hub.Post(MoveNodeResponse.Ok(movedNode), o => o.ResponseFor(request)); diff --git a/src/MeshWeaver.Mesh.Contract/Query/QueryParser.cs b/src/MeshWeaver.Mesh.Contract/Query/QueryParser.cs index fdecb6088..9d614d293 100644 --- a/src/MeshWeaver.Mesh.Contract/Query/QueryParser.cs +++ b/src/MeshWeaver.Mesh.Contract/Query/QueryParser.cs @@ -375,8 +375,17 @@ private string ParseSingleValue(string input, ref int i) if (field.Equals("namespace", StringComparison.OrdinalIgnoreCase)) { - path = value; - namespaceUsed = true; + if (value.Contains('*')) + { + // Wildcard namespace: add as LIKE filter (e.g., namespace:*/_Thread) + filterTokens.Add(new Token(TokenType.Comparison, null, + new QueryCondition("namespace", QueryOperator.Like, [value.Replace("*", "%")]))); + } + else + { + path = value; + namespaceUsed = true; + } continue; } diff --git a/src/MeshWeaver.Mesh.Contract/Security/UserAccess.cs b/src/MeshWeaver.Mesh.Contract/Security/UserAccess.cs index c36b1d292..d58d733e7 100644 --- a/src/MeshWeaver.Mesh.Contract/Security/UserAccess.cs +++ b/src/MeshWeaver.Mesh.Contract/Security/UserAccess.cs @@ -16,4 +16,11 @@ public static class WellKnownUsers /// Every logged-in user inherits "Public" permissions in addition to their own. /// public const string Public = "Public"; + + /// + /// The "system-security" identity used by SecurityService for internal operations. + /// Bypasses RLS validation — security operations (creating/updating AccessAssignment, + /// PartitionAccessPolicy nodes) must not be blocked by the permissions they manage. + /// + public const string System = "system-security"; } diff --git a/src/MeshWeaver.Mesh.Contract/Services/ICrossSchemaQueryProvider.cs b/src/MeshWeaver.Mesh.Contract/Services/ICrossSchemaQueryProvider.cs index 085e0e664..d4d0726a9 100644 --- a/src/MeshWeaver.Mesh.Contract/Services/ICrossSchemaQueryProvider.cs +++ b/src/MeshWeaver.Mesh.Contract/Services/ICrossSchemaQueryProvider.cs @@ -24,4 +24,16 @@ IAsyncEnumerable QueryAcrossSchemasAsync( IReadOnlyList schemas, string? userId = null, CancellationToken ct = default); + + /// + /// Queries a satellite table across multiple schemas in a single SQL UNION ALL query. + /// Used for satellite node types (Thread, Activity, etc.) that live in dedicated tables. + /// + IAsyncEnumerable QueryAcrossSchemasAsync( + ParsedQuery query, + JsonSerializerOptions options, + IReadOnlyList schemas, + string tableName, + string? userId = null, + CancellationToken ct = default); } diff --git a/src/MeshWeaver.Mesh.Contract/Services/IMeshChangeFeed.cs b/src/MeshWeaver.Mesh.Contract/Services/IMeshChangeFeed.cs new file mode 100644 index 000000000..560607745 --- /dev/null +++ b/src/MeshWeaver.Mesh.Contract/Services/IMeshChangeFeed.cs @@ -0,0 +1,64 @@ +namespace MeshWeaver.Mesh.Services; + +/// +/// Change feed for mesh data mutations (create/update/delete). +/// Producers call after each write. +/// Consumers call with optional filter. +/// In monolith: in-process Subject. In Orleans: BroadcastChannel cross-silo. +/// +public interface IMeshChangeFeed +{ + /// + /// Publishes a change event to all subscribers. + /// Called from persistence layer after each write. + /// + void Publish(MeshChangeEvent change); + + /// + /// Subscribes to change events with optional kind filter. + /// + /// Callback invoked for each matching event. + /// If set, only events matching this kind are delivered. + /// Disposable subscription. + IDisposable Subscribe(Action handler, MeshChangeKind? filter = null); +} + +/// +/// A mesh data change event emitted after a node is created, updated, or deleted. +/// +public record MeshChangeEvent( + string Namespace, + string Id, + string Path, + MeshChangeKind Kind, + string? NodeType, + long Version, + DateTimeOffset Timestamp +) +{ + public static MeshChangeEvent Created(MeshNode node) + => new(node.Namespace ?? "", node.Id, node.Path, MeshChangeKind.Created, + node.NodeType, node.Version, DateTimeOffset.UtcNow); + + public static MeshChangeEvent Updated(MeshNode node) + => new(node.Namespace ?? "", node.Id, node.Path, MeshChangeKind.Updated, + node.NodeType, node.Version, DateTimeOffset.UtcNow); + + public static MeshChangeEvent Deleted(string path, string? nodeType = null) + { + var segments = path.Split('/'); + var id = segments.Length > 0 ? segments[^1] : path; + var ns = segments.Length > 1 ? string.Join("/", segments[..^1]) : ""; + return new(ns, id, path, MeshChangeKind.Deleted, nodeType, 0, DateTimeOffset.UtcNow); + } +} + +/// +/// The kind of data change. +/// +public enum MeshChangeKind +{ + Created, + Updated, + Deleted +} diff --git a/src/MeshWeaver.Mesh.Contract/Services/IMeshQueryCore.cs b/src/MeshWeaver.Mesh.Contract/Services/IMeshQueryCore.cs index f61b0270e..3e99bfec2 100644 --- a/src/MeshWeaver.Mesh.Contract/Services/IMeshQueryCore.cs +++ b/src/MeshWeaver.Mesh.Contract/Services/IMeshQueryCore.cs @@ -1,14 +1,16 @@ +using System.Runtime.CompilerServices; using System.Text.Json; +[assembly: InternalsVisibleTo("MeshWeaver.Hosting.Blazor")] + namespace MeshWeaver.Mesh.Services; /// -/// Internal core query interface without access control. -/// Follows the same pattern as IStorageService (core) vs IMeshStorage (wrapper). -/// Used by infrastructure code (NodeTypeService, MeshCatalog, compilation) that needs -/// raw queries without user context. +/// Infrastructure query interface without access control. +/// Used by infrastructure code (login, NodeTypeService, compilation) that needs +/// raw queries without user context. Must not be exposed to application code. /// -public interface IMeshQueryCore +internal interface IMeshQueryCore { /// /// Query nodes without access control filtering. diff --git a/src/MeshWeaver.Messaging.Contract/HeartBeatEvent.cs b/src/MeshWeaver.Messaging.Contract/HeartBeatEvent.cs new file mode 100644 index 000000000..14f94bb23 --- /dev/null +++ b/src/MeshWeaver.Messaging.Contract/HeartBeatEvent.cs @@ -0,0 +1,23 @@ +namespace MeshWeaver.Messaging; + +/// +/// Published by executing hubs (e.g., _Exec during AI streaming) to their parent hub +/// to signal that the grain should stay alive during long-running operations. +/// Handled by every mesh node hub — calls GrainKeepAliveCallback if registered. +/// +public record HeartBeatEvent; + +/// +/// Registered on the hub configuration by the Orleans grain during activation. +/// Provides a bridge from the hub's HeartBeatEvent handler to the grain's DelayDeactivation. +/// In monolith mode, no callback is set — HeartBeatEvent is a no-op. +/// +public record GrainKeepAliveCallback(Action KeepAlive); + +/// +/// Callback registered by Orleans grain to support long-running operations. +/// The hub calls BeginOperation before starting an async operation (AI streaming, etc.). +/// The returned IDisposable stops the keep-alive when disposed. +/// In monolith mode, no callback is set — returns a no-op disposable. +/// +public record GrainLongRunningOperationCallback(Func BeginOperation); diff --git a/src/MeshWeaver.Messaging.Contract/IMessageDelivery.cs b/src/MeshWeaver.Messaging.Contract/IMessageDelivery.cs index ef2257a39..97a95a1d7 100644 --- a/src/MeshWeaver.Messaging.Contract/IMessageDelivery.cs +++ b/src/MeshWeaver.Messaging.Contract/IMessageDelivery.cs @@ -3,6 +3,8 @@ [assembly: InternalsVisibleTo("MeshWeaver.Messaging.Hub")] [assembly: InternalsVisibleTo("MeshWeaver.Hosting")] +[assembly: InternalsVisibleTo("MeshWeaver.Hosting.Orleans")] +[assembly: InternalsVisibleTo("MeshWeaver.AI")] namespace MeshWeaver.Messaging; diff --git a/src/MeshWeaver.Messaging.Hub/MessageHubExtensions.cs b/src/MeshWeaver.Messaging.Hub/MessageHubExtensions.cs index 4424d01b0..14db1d22a 100644 --- a/src/MeshWeaver.Messaging.Hub/MessageHubExtensions.cs +++ b/src/MeshWeaver.Messaging.Hub/MessageHubExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using System.Reactive.Linq; using System.Text.Json; using System.Text.Json.Nodes; using MeshWeaver.Domain; @@ -131,4 +132,30 @@ public static Address GetAddress(this IMessageHub hub, string address) var resultProperty = await hub.AwaitResponse(request, options, resultSelector, cancellationToken); return resultProperty; } + + /// + /// Starts a long-running operation scope that keeps the Orleans grain alive. + /// Uses GrainLongRunningOperationCallback (RegisterGrainTimer + DelayDeactivation) + /// when running in Orleans, falls back to Observable.Interval heartbeat otherwise. + /// Dispose the returned IDisposable when the operation completes. + /// In monolith mode, returns a no-op disposable. + /// + public static IDisposable BeginAsyncOperation(this IMessageHub hub) + { + // Walk parent chain to find the grain-level callback + var current = hub; + while (current != null) + { + var callback = current.Configuration.Get(); + if (callback != null) + return callback.BeginOperation(); + var parent = current.Configuration.ParentHub; + if (parent == current) break; + current = parent; + } + + // Fallback: heartbeat via Observable.Interval (monolith or no grain callback) + return Observable.Interval(TimeSpan.FromSeconds(25)) + .Subscribe(_ => hub.Post(new HeartBeatEvent())); + } } diff --git a/src/MeshWeaver.Messaging.Hub/Serialization/ReadOnlyCollectionConverterFactory.cs b/src/MeshWeaver.Messaging.Hub/Serialization/ReadOnlyCollectionConverterFactory.cs index ce7018dfe..140ebe253 100644 --- a/src/MeshWeaver.Messaging.Hub/Serialization/ReadOnlyCollectionConverterFactory.cs +++ b/src/MeshWeaver.Messaging.Hub/Serialization/ReadOnlyCollectionConverterFactory.cs @@ -134,28 +134,21 @@ public class ReadOnlyListConverter : JsonConverter> { public override IReadOnlyList Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - // For abstract types, interfaces, or types with polymorphic attributes, we need to deserialize each element individually - // using the polymorphic resolver to handle the actual concrete types - if (typeof(T).IsAbstract || typeof(T).IsInterface || HasPolymorphicAttributes(typeof(T))) - { - using var jsonDoc = JsonDocument.ParseValue(ref reader); - if (jsonDoc.RootElement.ValueKind != JsonValueKind.Array) - return new ReadOnlyCollection(Array.Empty()); + // Always parse each element individually via JsonDocument to handle + // $type metadata in any position (old data in PostgreSQL may have + // $type not as first property, which breaks Deserialize). + using var jsonDoc = JsonDocument.ParseValue(ref reader); + if (jsonDoc.RootElement.ValueKind != JsonValueKind.Array) + return new ReadOnlyCollection(Array.Empty()); - var list = new List(); - foreach (var element in jsonDoc.RootElement.EnumerateArray()) - { - var item = JsonSerializer.Deserialize(element.GetRawText(), options); - if (item != null) - list.Add(item); - } - return new ReadOnlyCollection(list); - } - else + var list = new List(); + foreach (var element in jsonDoc.RootElement.EnumerateArray()) { - var array = JsonSerializer.Deserialize(ref reader, options); - return array == null ? new ReadOnlyCollection(Array.Empty()) : new ReadOnlyCollection(array); + var item = JsonSerializer.Deserialize(element.GetRawText(), options); + if (item != null) + list.Add(item); } + return new ReadOnlyCollection(list); } public override void Write(Utf8JsonWriter writer, IReadOnlyList value, JsonSerializerOptions options) { diff --git a/test/MeshWeaver.AI.Test/SchemaValidationTest.cs b/test/MeshWeaver.AI.Test/SchemaValidationTest.cs index 1bb7a801f..e819d9cae 100644 --- a/test/MeshWeaver.AI.Test/SchemaValidationTest.cs +++ b/test/MeshWeaver.AI.Test/SchemaValidationTest.cs @@ -175,10 +175,9 @@ public async Task Create_WithSlashInId_SanitizesAndCreates() { var plugin = CreatePlugin(); - var uniqueSuffix = Guid.NewGuid().ToString("N")[..8]; var nodeJson = JsonSerializer.Serialize(new { - id = $"ACME/Product/PricingTool-{uniqueSuffix}", + id = "ACME/Product/PricingTool", @namespace = "", name = "Pricing Tool", nodeType = "Markdown" diff --git a/test/MeshWeaver.AI.Test/ThreadAgentIntegrationTest.cs b/test/MeshWeaver.AI.Test/ThreadAgentIntegrationTest.cs index b0dd2ec50..8dbadc49a 100644 --- a/test/MeshWeaver.AI.Test/ThreadAgentIntegrationTest.cs +++ b/test/MeshWeaver.AI.Test/ThreadAgentIntegrationTest.cs @@ -160,7 +160,6 @@ public async Task FullFlow_CreateThread_SendMessage_StreamResponse_SaveReply() var messageId = Guid.NewGuid().AsString(); var userMessage = new ThreadMessage { - Id = messageId, Role = "user", Text = "What is the status of the product launch?", Timestamp = DateTime.UtcNow, @@ -217,7 +216,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode($"{threadPath}/{messageId}") var replyId = Guid.NewGuid().AsString(); var replyMessage = new ThreadMessage { - Id = replyId, Role = "assistant", AuthorName = agents[0].Name, Text = responseText, diff --git a/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs b/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs index 8b411af77..4fce466fd 100644 --- a/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs +++ b/test/MeshWeaver.Acme.Test/TodoCreateFlowTest.cs @@ -701,9 +701,7 @@ await meshQuery Output.WriteLine("Node confirmed as Active."); // Step 5: Use GetDataRequest to retrieve the MeshNode via EntityReference - // MeshNode key is Id (last segment), not full path - var nodeId = nodePath[(nodePath.LastIndexOf('/') + 1)..]; - var entityRef = new EntityReference(nameof(MeshNode), nodeId); + var entityRef = new EntityReference(nameof(MeshNode), nodePath); var getDataResponse = await client.AwaitResponse( new GetDataRequest(entityRef), o => o.WithTarget(nodeAddress), diff --git a/test/MeshWeaver.Content.Test/ContentReferenceIntegrityTest.cs b/test/MeshWeaver.Content.Test/ContentReferenceIntegrityTest.cs index 3608f1c0a..03fbad6d3 100644 --- a/test/MeshWeaver.Content.Test/ContentReferenceIntegrityTest.cs +++ b/test/MeshWeaver.Content.Test/ContentReferenceIntegrityTest.cs @@ -145,6 +145,10 @@ public async Task Validate_MarkdownNodeIcons_AreValidReferences() if (!icon.Contains('/')) continue; + // Skip inline SVG icons (valid icon format, not a file path) + if (icon.TrimStart().StartsWith(" +/// Tests for docx → markdown conversion via IContentTransformer, +/// content autocomplete for document files, and agent content access. +/// +public class DocxConversionTest(ITestOutputHelper output) : HubTestBase(output) +{ + private readonly string _contentBasePath = Path.Combine(AppContext.BaseDirectory, "Files", "DocxTest"); + + protected override MessageHubConfiguration ConfigureClient(MessageHubConfiguration configuration) + { + Directory.CreateDirectory(_contentBasePath); + CreateTestDocx(Path.Combine(_contentBasePath, "sample.docx"), "Hello World", "This is a test document."); + // Also create a plain text file for comparison + File.WriteAllText(Path.Combine(_contentBasePath, "readme.md"), "# Readme\nSome text."); + + return base.ConfigureClient(configuration) + .AddContentCollection(_ => new ContentCollectionConfig + { + Name = "content", + SourceType = "FileSystem", + IsEditable = true, + BasePath = _contentBasePath, + Settings = new Dictionary + { + ["BasePath"] = _contentBasePath + } + }); + } + + [Fact] + public async Task DocSharpContentTransformer_Converts_Docx_To_Markdown() + { + // Arrange + var transformer = new DocSharpContentTransformer(); + transformer.SupportedExtensions.Should().Contain(".docx"); + + var docxPath = Path.Combine(_contentBasePath, "sample.docx"); + await using var stream = File.OpenRead(docxPath); + + // Act + var markdown = await transformer.TransformToMarkdownAsync(stream, TestContext.Current.CancellationToken); + + // Assert + Output.WriteLine($"Converted markdown:\n{markdown}"); + markdown.Should().NotBeNullOrWhiteSpace(); + markdown.Should().Contain("Hello World"); + markdown.Should().Contain("test document"); + } + + [Fact] + public async Task FileContentProvider_Auto_Converts_Docx() + { + // Arrange + var hub = GetClient(); + var fileContentProvider = hub.ServiceProvider.GetRequiredService(); + + // Act — requesting a .docx file should auto-convert to markdown + var result = await fileContentProvider.GetFileContentAsync("content", "sample.docx", ct: TestContext.Current.CancellationToken); + + // Assert + Output.WriteLine($"Content result:\n{result.Content}"); + result.Success.Should().BeTrue(); + result.Content.Should().NotBeNullOrWhiteSpace(); + result.Content.Should().Contain("Hello World"); + result.Content.Should().Contain("test document"); + } + + [Fact] + public async Task FileContentProvider_Returns_PlainText_For_Md() + { + // Arrange + var hub = GetClient(); + var fileContentProvider = hub.ServiceProvider.GetRequiredService(); + + // Act — requesting a .md file should return as-is + var result = await fileContentProvider.GetFileContentAsync("content", "readme.md", ct: TestContext.Current.CancellationToken); + + // Assert + result.Success.Should().BeTrue(); + result.Content.Should().Contain("# Readme"); + result.Content.Should().Contain("Some text."); + } + + [Fact] + public async Task ContentAutocomplete_Filters_And_Scores_By_Query() + { + // Arrange + var hub = GetClient(); + var providers = hub.ServiceProvider.GetServices(); + var contentProvider = providers + .OfType() + .FirstOrDefault(); + contentProvider.Should().NotBeNull("ContentAutocompleteProvider should be registered"); + + // Act — query "sample" should match sample.docx but NOT readme.md + var items = new List(); + await foreach (var item in contentProvider!.GetItemsAsync("sample", ct: TestContext.Current.CancellationToken)) + { + items.Add(item); + } + + // Assert — only matching files returned + Output.WriteLine($"Autocomplete items for 'sample': {items.Count}"); + foreach (var item in items) + Output.WriteLine($" [{item.Priority}] {item.Label} => {item.InsertText}"); + + items.Should().Contain(i => i.Label == "sample.docx"); + items.Should().NotContain(i => i.Label == "readme.md", "non-matching files should be filtered out"); + + var docxItem = items.First(i => i.Label == "sample.docx"); + docxItem.InsertText.Should().Contain("content:"); + docxItem.InsertText.Should().NotContain("content:content/", "should not have duplicate content prefix"); + docxItem.Description.Should().Contain("converts to markdown"); + docxItem.Kind.Should().Be(AutocompleteKind.File); + docxItem.Priority.Should().BeGreaterThan(2000, "prefix match should get high priority"); + } + + [Fact] + public async Task ContentAutocomplete_ExactMatch_Gets_Highest_Priority() + { + // Arrange + var hub = GetClient(); + var providers = hub.ServiceProvider.GetServices(); + var contentProvider = providers + .OfType() + .FirstOrDefault(); + contentProvider.Should().NotBeNull(); + + // Act — exact name match + var items = new List(); + await foreach (var item in contentProvider!.GetItemsAsync("sample.docx", ct: TestContext.Current.CancellationToken)) + { + items.Add(item); + } + + // Assert — exact match should score 3000 + var docxItem = items.First(i => i.Label == "sample.docx"); + docxItem.Priority.Should().Be(3000, "exact name match should get highest score"); + } + + [Fact] + public async Task ContentAutocomplete_Wraps_Spaces_In_Quotes() + { + // Arrange — create a file with spaces in the name + File.WriteAllText(Path.Combine(_contentBasePath, "my document.docx"), ""); + // Create a valid docx instead + CreateTestDocx(Path.Combine(_contentBasePath, "my document.docx"), "Spaced Doc", "Content"); + + var hub = GetClient(); + var providers = hub.ServiceProvider.GetServices(); + var contentProvider = providers + .OfType() + .FirstOrDefault(); + + // Act + var items = new List(); + await foreach (var item in contentProvider!.GetItemsAsync("my doc", ct: TestContext.Current.CancellationToken)) + { + items.Add(item); + } + + // Assert + Output.WriteLine($"Items for 'my doc': {items.Count}"); + foreach (var item in items) + Output.WriteLine($" {item.Label} => {item.InsertText}"); + + var spacedItem = items.FirstOrDefault(i => i.Label == "my document.docx"); + spacedItem.Should().NotBeNull("file with spaces should be found"); + spacedItem!.InsertText.Should().StartWith("\"", "paths with spaces should be quoted"); + spacedItem.InsertText.Should().EndWith("\" ", "paths with spaces should be quoted with trailing space"); + } + + [Fact] + public async Task GetDataRequest_Content_Prefix_Returns_Markdown_For_Docx() + { + // Arrange — the unified path content:content/sample.docx should auto-convert + var hub = GetClient(); + var request = new GetDataRequest(new UnifiedReference("content:content/sample.docx")); + var delivery = hub.Post(request, o => o.WithTarget(hub.Address))!; + + // Act + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var response = await hub.RegisterCallback(delivery, (d, _) => Task.FromResult(d), cts.Token); + + // Assert + response.Should().BeAssignableTo>(); + var dataResponse = ((IMessageDelivery)response).Message; + Output.WriteLine($"Response data: {dataResponse.Data}"); + dataResponse.Error.Should().BeNull(); + dataResponse.Data.Should().NotBeNull(); + dataResponse.Data!.ToString().Should().Contain("Hello World"); + } + + /// + /// Creates a minimal .docx file with a heading and body paragraph. + /// + private static void CreateTestDocx(string path, string heading, string bodyText) + { + using var doc = WordprocessingDocument.Create(path, WordprocessingDocumentType.Document); + var mainPart = doc.AddMainDocumentPart(); + mainPart.Document = new Document(); + var body = mainPart.Document.AppendChild(new Body()); + + // Add heading + var headingParagraph = body.AppendChild(new Paragraph()); + var headingRun = headingParagraph.AppendChild(new Run()); + headingRun.AppendChild(new Text(heading)); + headingParagraph.ParagraphProperties = new ParagraphProperties( + new ParagraphStyleId { Val = "Heading1" }); + + // Add body text + var bodyParagraph = body.AppendChild(new Paragraph()); + var bodyRun = bodyParagraph.AppendChild(new Run()); + bodyRun.AppendChild(new Text(bodyText)); + } +} diff --git a/test/MeshWeaver.ContentCollections.Test/MeshWeaver.ContentCollections.Test.csproj b/test/MeshWeaver.ContentCollections.Test/MeshWeaver.ContentCollections.Test.csproj index ea0051db3..97ed4b195 100644 --- a/test/MeshWeaver.ContentCollections.Test/MeshWeaver.ContentCollections.Test.csproj +++ b/test/MeshWeaver.ContentCollections.Test/MeshWeaver.ContentCollections.Test.csproj @@ -3,6 +3,7 @@ {8B5E3C7D-9A2F-4B1E-8D6C-3F7A9E1B4C2D} + diff --git a/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs b/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs index e1b2ea6ca..d8bc66dac 100644 --- a/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs +++ b/test/MeshWeaver.FutuRe.Test/FutuReAnalysisTest.cs @@ -44,8 +44,6 @@ protected override MeshBuilder ConfigureMesh(MeshBuilder builder) { var graphPath = TestPaths.SamplesGraph; var dataDirectory = TestPaths.SamplesGraphData; - if (Directory.Exists(SharedCacheDirectory)) - Directory.Delete(SharedCacheDirectory, recursive: true); Directory.CreateDirectory(SharedCacheDirectory); var configuration = new ConfigurationBuilder() @@ -545,22 +543,6 @@ await client.AwaitResponse( "Default area for Analysis hub should be 'LayoutAreas' (profitability catalog), not 'Overview'"); } - // ── Analysis Overview rendering (catches null stream / access control crashes) ── - - [Fact(Timeout = 20000)] - public async Task EuropeRe_Analysis_Overview_ShouldRender() - { - var control = await GetControlAsync("FutuRe/EuropeRe/Analysis", "Overview"); - control.Should().NotBeNull("EuropeRe Analysis Overview should render without crashing"); - } - - [Fact(Timeout = 20000)] - public async Task AmericasIns_Analysis_Overview_ShouldRender() - { - var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "Overview"); - control.Should().NotBeNull("AmericasIns Analysis Overview should render without crashing"); - } - // ── Local Analysis Hub (EuropeRe) ── [Fact(Timeout = 20000)] @@ -575,11 +557,10 @@ public async Task EuropeRe_KeyMetrics_ShouldHaveNonZeroData() [Fact(Timeout = 20000)] public async Task EuropeRe_KeyMetrics_ShouldShowCorrectCurrency() { - // With group-level aggregation enabled, the local hub converts to CHF (group currency) - // via the currency toolbar (default mode: Plan CHF). var control = await GetControlAsync("FutuRe/EuropeRe/Analysis", "KeyMetrics", unwrap: true); var md = AssertMarkdownWithNonZeroNumbers(control, "EuropeRe KeyMetrics currency"); - md.Should().Contain(" CHF", "EuropeRe local hub now aggregates to group level with default Plan CHF mode"); + md.Should().Contain(" EUR", "EuropeRe amounts should be labeled with EUR, not CHF"); + md.Should().NotContain(" CHF", "EuropeRe should not show CHF — its currency is EUR"); } [Fact(Timeout = 20000)] @@ -788,122 +769,6 @@ public async Task Group_AnnualProfitabilityWaterfall_ShouldRender() control.Should().BeOfType("AnnualProfitabilityWaterfall should return an HtmlControl with SVG"); } - [Fact(Timeout = 30000)] - public async Task Group_GroupProfitabilityDashboard_ShouldRender() - { - await InitializeChildAnalysisHubs(); - var control = await GetControlAsync("FutuRe/Analysis", "GroupProfitabilityDashboard", unwrap: false); - var stack = control.Should().BeOfType().Subject; - // Toolbar wraps content: top-level StackControl has [toolbar, content] - stack.Areas.Should().HaveCountGreaterThanOrEqualTo(2, - "GroupProfitabilityDashboard should contain toolbar and dashboard content"); - } - - [Fact(Timeout = 30000)] - public async Task Group_Analysis_DefaultArea_ShouldResolveToLayoutAreas() - { - await InitializeChildAnalysisHubs(); - var client = GetClient(); - var address = new Address("FutuRe/Analysis"); - - await client.AwaitResponse( - new PingRequest(), - o => o.WithTarget(address), - TestContext.Current.CancellationToken); - - var workspace = client.GetWorkspace(); - var reference = new LayoutAreaReference((string?)null); - - var stream = workspace.GetRemoteStream( - address, reference); - - var control = await stream - .GetControlStream("") - .Timeout(TimeSpan.FromSeconds(15)) - .FirstAsync(x => x is not null); - - var namedArea = control.Should().BeOfType().Subject; - namedArea.Area.Should().Be("LayoutAreas", - "Default area for group Analysis hub should be 'LayoutAreas' (profitability catalog)"); - } - - // ── Local Analysis Hub (AmericasIns) ── - - [Fact(Timeout = 20000)] - public async Task AmericasIns_KeyMetrics_ShouldHaveNonZeroData() - { - var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "KeyMetrics", unwrap: true); - var md = AssertMarkdownWithNonZeroNumbers(control, "AmericasIns KeyMetrics"); - md.Should().Contain("Total Premium", "KeyMetrics should show premium"); - md.Should().Contain("Loss Ratio", "KeyMetrics should show loss ratio"); - } - - [Fact(Timeout = 20000)] - public async Task AmericasIns_ProfitabilityTable_ShouldHaveNonZeroData() - { - var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "ProfitabilityTable", unwrap: true); - var md = AssertMarkdownWithNonZeroNumbers(control, "AmericasIns ProfitabilityTable"); - md.Should().Contain("Line of Business", "table should have headers"); - md.Should().Contain("Total", "table should have totals row"); - } - - [Fact(Timeout = 20000)] - public async Task AmericasIns_ProfitabilityOverview_ShouldRenderChart() - { - var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "ProfitabilityOverview", unwrap: true); - control.Should().BeOfType("ProfitabilityOverview should be a chart"); - } - - [Fact(Timeout = 20000)] - public async Task AmericasIns_AnnualProfitabilityWaterfall_ShouldRender() - { - var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "AnnualProfitabilityWaterfall", unwrap: true); - control.Should().BeOfType("AnnualProfitabilityWaterfall should return an HtmlControl with SVG"); - } - - [Fact(Timeout = 20000)] - public async Task AmericasIns_Analysis_DefaultArea_ShouldResolveToLayoutAreas() - { - var client = GetClient(); - var address = new Address("FutuRe/AmericasIns/Analysis"); - - await client.AwaitResponse( - new PingRequest(), - o => o.WithTarget(address), - TestContext.Current.CancellationToken); - - var workspace = client.GetWorkspace(); - var reference = new LayoutAreaReference((string?)null); - - var stream = workspace.GetRemoteStream( - address, reference); - - var control = await stream - .GetControlStream("") - .Timeout(TimeSpan.FromSeconds(15)) - .FirstAsync(x => x is not null); - - var namedArea = control.Should().BeOfType().Subject; - namedArea.Area.Should().Be("LayoutAreas", - "Default area for AmericasIns Analysis hub should be 'LayoutAreas' (profitability catalog)"); - } - - [Fact(Timeout = 20000)] - public async Task AmericasIns_Analysis_LayoutAreas_ShouldRenderCatalog() - { - var control = await GetControlAsync("FutuRe/AmericasIns/Analysis", "LayoutAreas"); - control.Should().NotBeNull("LayoutAreas catalog should render for AmericasIns Analysis hub"); - - var stack = control.Should().BeOfType().Subject; - Output.WriteLine($"LayoutAreas catalog has {stack.Areas?.Count ?? 0} areas"); - - stack.Areas.Should().HaveCountGreaterThanOrEqualTo(2, - "Catalog should have at least one category header (H2) + one grid of layout area tiles"); - - control.Should().NotBeOfType( - "LayoutAreas should show a catalog of profitability views, not a search/overview"); - } - // ── Business Unit Layout Areas ── /// @@ -1022,6 +887,69 @@ await client.AwaitResponse( "AnnualReport Overview should render the report content"); } + // ── AnnualReport Diagnostic Tests ── + + /// + /// Diagnostic: verify that the AnnualReport Overview contains @@() layout area references + /// in its markdown content, and that the Markdig pipeline converts them to layout-area divs. + /// + [Fact(Timeout = 30000)] + public async Task AnnualReport_Overview_ShouldContainLayoutAreaReferences() + { + var client = GetClient(); + var address = new Address("FutuRe/Analysis/AnnualReport"); + + await client.AwaitResponse(new PingRequest(), o => o.WithTarget(address), + TestContext.Current.CancellationToken); + + var workspace = client.GetWorkspace(); + var reference = new LayoutAreaReference("Overview"); + var stream = workspace.GetRemoteStream(address, reference); + + // Get the Overview control (StackControl with title + MarkdownControl + children) + var control = await stream.GetControlStream(reference.Area!) + .Timeout(TimeSpan.FromSeconds(15)) + .FirstAsync(x => x is not null); + + var stack = control.Should().BeOfType().Subject; + Output.WriteLine($"Stack has {stack.Areas?.Count} areas"); + + // Iterate through child areas to find the MarkdownControl + var foundMarkdown = false; + foreach (var area in stack.Areas ?? []) + { + var childKey = area.Area?.ToString(); + if (string.IsNullOrEmpty(childKey)) continue; + + var childControl = await stream.GetControlStream(childKey) + .Timeout(TimeSpan.FromSeconds(10)) + .FirstAsync(x => x is not null); + + Output.WriteLine($" Area '{childKey}': {childControl?.GetType().Name}"); + + if (childControl is MarkdownControl md) + { + foundMarkdown = true; + var markdown = md.Markdown?.ToString() ?? ""; + Output.WriteLine($" Markdown length: {markdown.Length}"); + Output.WriteLine($" Contains @@: {markdown.Contains("@@")}"); + Output.WriteLine($" First 500 chars: {markdown[..Math.Min(500, markdown.Length)]}"); + + markdown.Should().Contain("@@(", "Report markdown should contain @@() layout area references"); + + // Process through Markdig to verify HTML output + var pipeline = MeshWeaver.Markdown.MarkdownExtensions.CreateMarkdownPipeline(null); + var html = Markdig.Markdown.ToHtml(markdown, pipeline); + Output.WriteLine($" HTML contains layout-area: {html.Contains("layout-area")}"); + Output.WriteLine($" HTML snippet: {html[..Math.Min(500, html.Length)]}"); + + html.Should().Contain("layout-area", "Markdig should convert @@() to layout-area divs"); + } + } + + foundMarkdown.Should().BeTrue("Overview stack should contain a MarkdownControl with report body"); + } + /// /// Diagnostic: verify that IPathResolver resolves FutuRe/Analysis/X paths correctly, /// splitting into Prefix="FutuRe/Analysis" and Remainder="X". @@ -1068,6 +996,69 @@ public async Task AnnualReport_EmbeddedCharts_ShouldRenderViaPathResolution() control.Should().NotBeNull("KeyMetrics should render when accessed via path resolution"); } + // ── EuropeRe AnnualReport ── + + /// + /// Verifies that the EuropeRe AnnualReport Overview contains @@() layout area references + /// in its markdown content, and that Markdig converts them to layout-area divs. + /// Since EuropeRe charts render individually, this report should work end-to-end. + /// + [Fact(Timeout = 30000)] + public async Task EuropeRe_AnnualReport_Overview_ShouldContainLayoutAreaReferences() + { + var client = GetClient(); + var address = new Address("FutuRe/EuropeRe/Analysis/AnnualReport"); + + await client.AwaitResponse(new PingRequest(), o => o.WithTarget(address), + TestContext.Current.CancellationToken); + + var workspace = client.GetWorkspace(); + var reference = new LayoutAreaReference("Overview"); + var stream = workspace.GetRemoteStream(address, reference); + + var control = await stream.GetControlStream(reference.Area!) + .Timeout(TimeSpan.FromSeconds(15)) + .FirstAsync(x => x is not null); + + var stack = control.Should().BeOfType().Subject; + Output.WriteLine($"Stack has {stack.Areas?.Count} areas"); + + var foundMarkdown = false; + foreach (var area in stack.Areas ?? []) + { + var childKey = area.Area?.ToString(); + if (string.IsNullOrEmpty(childKey)) continue; + + var childControl = await stream.GetControlStream(childKey) + .Timeout(TimeSpan.FromSeconds(10)) + .FirstAsync(x => x is not null); + + Output.WriteLine($" Area '{childKey}': {childControl?.GetType().Name}"); + + if (childControl is MarkdownControl md) + { + foundMarkdown = true; + var markdown = md.Markdown?.ToString() ?? ""; + Output.WriteLine($" Markdown length: {markdown.Length}"); + Output.WriteLine($" Contains @@: {markdown.Contains("@@")}"); + Output.WriteLine($" First 500 chars: {markdown[..Math.Min(500, markdown.Length)]}"); + + markdown.Should().Contain("@@(", "EuropeRe report markdown should contain @@() layout area references"); + markdown.Should().Contain("FutuRe/EuropeRe/Analysis/KeyMetrics", + "Report should reference EuropeRe-specific chart paths"); + + var pipeline = MeshWeaver.Markdown.MarkdownExtensions.CreateMarkdownPipeline(null); + var html = Markdig.Markdown.ToHtml(markdown, pipeline); + Output.WriteLine($" HTML contains layout-area: {html.Contains("layout-area")}"); + Output.WriteLine($" HTML snippet: {html[..Math.Min(500, html.Length)]}"); + + html.Should().Contain("layout-area", "Markdig should convert @@() to layout-area divs"); + } + } + + foundMarkdown.Should().BeTrue("EuropeRe Overview stack should contain a MarkdownControl with report body"); + } + /// /// Verifies that IPathResolver resolves EuropeRe analysis chart paths correctly, /// splitting e.g. "FutuRe/EuropeRe/Analysis/KeyMetrics" into @@ -1168,7 +1159,7 @@ public async Task Group_HubInitialization_ShouldSucceedWithoutPreInit() /// Pre-initializes child BU analysis hubs (EuropeRe, AmericasIns) so their data /// is loaded before the group hub's PartitionedHubDataSource tries to aggregate. /// Without this, the remote streams may receive empty data if child hubs haven't - /// finished loading their datacube from node content when the group hub subscribes. + /// finished loading their CSV data when the group hub subscribes. /// private async Task InitializeChildAnalysisHubs() { diff --git a/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs b/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs index 37315948f..2de656430 100644 --- a/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs +++ b/test/MeshWeaver.FutuRe.Test/FxConversionTest.cs @@ -38,13 +38,13 @@ public class FxConversionTest { Id = "EUR-HOUSEHOLD-PROPERTY", BusinessUnit = "EuropeRe", LocalLineOfBusiness = "HOUSEHOLD", - GroupLineOfBusiness = "PROPERTY", Percentage = 100 + GroupLineOfBusiness = "PROPERTY", Percentage = 1.0 }, new() { Id = "AME-CASUALTY-CASUALTY", BusinessUnit = "AmericasIns", LocalLineOfBusiness = "CASUALTY", - GroupLineOfBusiness = "CASUALTY", Percentage = 100 + GroupLineOfBusiness = "CASUALTY", Percentage = 1.0 } ]; @@ -196,20 +196,20 @@ public void PartialPercentageMapping_SplitsRowCorrectly() } }; - // 2 mappings: HOUSEHOLD → PROPERTY at 60, HOUSEHOLD → CASUALTY at 40 + // 2 mappings: HOUSEHOLD → PROPERTY at 60%, HOUSEHOLD → CASUALTY at 40% var mappings = new[] { new TransactionMapping { Id = "EUR-HOUSEHOLD-PROPERTY", BusinessUnit = "EuropeRe", LocalLineOfBusiness = "HOUSEHOLD", GroupLineOfBusiness = "PROPERTY", - Percentage = 60 + Percentage = 0.6 }, new TransactionMapping { Id = "EUR-HOUSEHOLD-CASUALTY", BusinessUnit = "EuropeRe", LocalLineOfBusiness = "HOUSEHOLD", GroupLineOfBusiness = "CASUALTY", - Percentage = 40 + Percentage = 0.4 } }; @@ -278,7 +278,7 @@ public void MissingExchangeRate_FallsBackToOne() { Id = "ASIA-MARINE-MARINE", BusinessUnit = "AsiaRe", LocalLineOfBusiness = "MARINE", GroupLineOfBusiness = "MARINE", - Percentage = 100 + Percentage = 1.0 } }; @@ -410,7 +410,7 @@ public void ChfBusinessUnit_NoConversionApplied() { Id = "CHE-PROPERTY-PROPERTY", BusinessUnit = "SwissRe", LocalLineOfBusiness = "PROPERTY", GroupLineOfBusiness = "PROPERTY", - Percentage = 100 + Percentage = 1.0 } }; diff --git a/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj b/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj index ccce9f9c0..89afe9101 100644 --- a/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj +++ b/test/MeshWeaver.FutuRe.Test/MeshWeaver.FutuRe.Test.csproj @@ -23,7 +23,6 @@ - diff --git a/test/MeshWeaver.Hosting.Monolith.Test/MeshChangeFeedTest.cs b/test/MeshWeaver.Hosting.Monolith.Test/MeshChangeFeedTest.cs new file mode 100644 index 000000000..035ee7d72 --- /dev/null +++ b/test/MeshWeaver.Hosting.Monolith.Test/MeshChangeFeedTest.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using System.Reactive.Linq; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using MeshWeaver.Data; +using MeshWeaver.Graph; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Hosting.Monolith.TestBase; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace MeshWeaver.Hosting.Monolith.Test; + +/// +/// Tests for the MeshChangeFeed: events are published on create/delete, +/// filtered subscriptions work, and path resolver cache is invalidated correctly. +/// +public class MeshChangeFeedTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => base.ConfigureMesh(builder) + .AddGraph(); + + private IMeshChangeFeed ChangeFeed => Mesh.ServiceProvider.GetRequiredService(); + private IPathResolver PathResolver => Mesh.ServiceProvider.GetRequiredService(); + private CancellationToken Ct => new CancellationTokenSource(10_000).Token; + + private async Task CreateTestNodeAsync(string id, string? ns = null) + { + var node = new MeshNode(id, ns) { Name = $"Test {id}", NodeType = "Markdown" }; + var response = await Mesh.AwaitResponse( + new CreateNodeRequest(node), o => o.WithTarget(Mesh.Address), Ct); + response.Message.Success.Should().BeTrue(response.Message.Error); + return response.Message.Node!; + } + + private async Task DeleteTestNodeAsync(string path) + { + var response = await Mesh.AwaitResponse( + new DeleteNodeRequest(path), o => o.WithTarget(Mesh.Address), Ct); + response.Message.Error.Should().BeNullOrEmpty(); + } + + [Fact] + public async Task CreateNode_PublishesCreatedEvent() + { + var events = new List(); + using var sub = ChangeFeed.Subscribe(e => events.Add(e)); + + await CreateTestNodeAsync("feed-create-1"); + + events.Should().Contain(e => e.Kind == MeshChangeKind.Created && e.Id == "feed-create-1"); + } + + [Fact] + public async Task DeleteNode_PublishesDeletedEvent() + { + var created = await CreateTestNodeAsync("feed-del-1"); + + var events = new List(); + using var sub = ChangeFeed.Subscribe(e => events.Add(e)); + + await DeleteTestNodeAsync(created.Path); + + events.Should().Contain(e => e.Kind == MeshChangeKind.Deleted && e.Path.Contains("feed-del-1")); + } + + [Fact] + public async Task FilteredSubscription_OnlyReceivesMatchingEvents() + { + var createEvents = new List(); + var deleteEvents = new List(); + using var createSub = ChangeFeed.Subscribe(e => createEvents.Add(e), MeshChangeKind.Created); + using var deleteSub = ChangeFeed.Subscribe(e => deleteEvents.Add(e), MeshChangeKind.Deleted); + + var created = await CreateTestNodeAsync("feed-filter-1"); + await DeleteTestNodeAsync(created.Path); + + createEvents.Should().OnlyContain(e => e.Kind == MeshChangeKind.Created); + deleteEvents.Should().OnlyContain(e => e.Kind == MeshChangeKind.Deleted); + } + + [Fact] + public async Task CreateNode_PathResolverFindsIt() + { + // Resolve before create — should not find it + var before = await PathResolver.ResolvePathAsync("feed-resolve-1"); + + await CreateTestNodeAsync("feed-resolve-1"); + + // After create — cache was invalidated/pre-warmed by change event + var after = await PathResolver.ResolvePathAsync("feed-resolve-1"); + after.Should().NotBeNull(); + after!.Prefix.Should().Contain("feed-resolve-1"); + after.Remainder.Should().BeNullOrEmpty(); + } + + [Fact] + public async Task DeleteNode_PathResolverNoLongerFindsIt() + { + var created = await CreateTestNodeAsync("feed-gone-1"); + + // Verify resolver finds it + var exists = await PathResolver.ResolvePathAsync(created.Path); + exists.Should().NotBeNull(); + + await DeleteTestNodeAsync(created.Path); + + // After delete — cache evicted, resolver should not find it at that exact path + var gone = await PathResolver.ResolvePathAsync(created.Path); + (gone == null || gone.Prefix != created.Path).Should().BeTrue( + "deleted node should not resolve to its exact path"); + } + + [Fact] + public async Task NestedCreate_EvictsParentPartialMatch() + { + // Create parent + var parent = await CreateTestNodeAsync("nest-parent-1"); + + // Resolve nested path — caches partial match (parent with remainder) + var partial = await PathResolver.ResolvePathAsync($"{parent.Path}/nest-child-1"); + + // Create child + await CreateTestNodeAsync("nest-child-1", parent.Path); + + // Now nested path should resolve to child (stale cache evicted by Created event) + var afterChild = await PathResolver.ResolvePathAsync($"{parent.Path}/nest-child-1"); + afterChild.Should().NotBeNull(); + afterChild!.Prefix.Should().Be($"{parent.Path}/nest-child-1"); + afterChild.Remainder.Should().BeNullOrEmpty(); + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/DelegationCompletionTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/DelegationCompletionTest.cs new file mode 100644 index 000000000..21b014384 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/DelegationCompletionTest.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using Xunit; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Tests that a SubmitMessageRequest returns TWO SubmitMessageResponse messages: +/// 1. Status=CellsCreated (cells created, execution starting) +/// 2. Status=ExecutionCompleted (agent finished, response text available) +/// +/// This is critical for delegation: the parent thread's RegisterCallback +/// waits for the second response to resolve the delegation TCS. +/// Without it, the parent thread hangs forever after delegation. +/// +public class DelegationCompletionTest(ITestOutputHelper output) : TestBase(output) +{ + private TestCluster Cluster { get; set; } = null!; + private IMessageHub ClientMesh => Cluster.Client.ServiceProvider.GetRequiredService(); + + public override async ValueTask InitializeAsync() + { + await base.InitializeAsync(); + var builder = new TestClusterBuilder(); + builder.AddSiloBuilderConfigurator(); + builder.AddClientBuilderConfigurator(); + Cluster = builder.Build(); + await Cluster.DeployAsync(); + } + + public override async ValueTask DisposeAsync() + { + if (Cluster is not null) + await Cluster.DisposeAsync(); + await base.DisposeAsync(); + } + + private async Task GetClientAsync() + { + var client = ClientMesh.ServiceProvider.CreateMessageHub( + new Address("client", "completion"), + config => + { + config.TypeRegistry.AddAITypes(); + return config.AddLayoutClient(); + }); + var accessService = client.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext + { + ObjectId = "Roland", + Name = "Roland Buergi" + }); + await Cluster.Client.ServiceProvider.GetRequiredService() + .RegisterStreamAsync(client.Address, client.DeliverMessage); + return client; + } + + /// + /// Verifies that SubmitMessageRequest produces two responses: + /// 1. CellsCreated (immediate) + /// 2. ExecutionCompleted (after agent finishes streaming) + /// + /// The test uses RegisterCallback (same pattern as delegation tool) + /// and collects all responses until ExecutionCompleted arrives. + /// + [Fact(Timeout = 60000)] + public async Task SubmitMessage_ReceivesBothCellsCreated_AndExecutionCompleted() + { + var ct = new CancellationTokenSource(50.Seconds()).Token; + var client = await GetClientAsync(); + + // Create thread + var response = await client.AwaitResponse( + new CreateNodeRequest(ThreadNodeType.BuildThreadNode("User/Roland", "Completion test", "Roland")), + o => o.WithTarget(new Address("User/Roland")), ct); + response.Message.Success.Should().BeTrue(response.Message.Error); + var threadPath = response.Message.Node!.Path!; + Output.WriteLine($"Thread: {threadPath}"); + + // Post SubmitMessageRequest and collect responses via RegisterCallback + var responses = new List<(SubmitMessageStatus Status, bool Success, string? ResponseText)>(); + var completionTcs = new TaskCompletionSource(); + + var delivery = client.Post( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Test completion notification", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath))); + delivery.Should().NotBeNull("Post should return delivery"); + + // RegisterCallback removes after first invocation — re-register for second response + void RegisterForResponse(IMessageDelivery del) + { + _ = client.RegisterCallback(del, cb => + { + if (cb is IMessageDelivery sr) + { + var msg = sr.Message; + Output.WriteLine($"Response: Status={msg.Status}, Success={msg.Success}, Error={msg.Error}, TextLen={msg.ResponseText?.Length ?? 0}"); + responses.Add((msg.Status, msg.Success, msg.ResponseText)); + + if (msg.Status == SubmitMessageStatus.CellsCreated) + RegisterForResponse(del); // Re-register for completion + else + completionTcs.TrySetResult(msg.Success); + } + else if (cb is IMessageDelivery df) + { + Output.WriteLine($"DeliveryFailure: {df.Message.Message}"); + completionTcs.TrySetResult(false); + } + return cb; + }); + } + RegisterForResponse((IMessageDelivery)delivery!); + + // Wait for execution to complete (with timeout) + var timeoutTask = Task.Delay(45_000, ct); + var completed = await Task.WhenAny(completionTcs.Task, timeoutTask); + if (completed == timeoutTask) + { + Output.WriteLine($"TIMEOUT! Received {responses.Count} response(s): [{string.Join(", ", responses.Select(r => r.Status))}]"); + } + completed.Should().Be(completionTcs.Task, + "should receive ExecutionCompleted before timeout — parent thread would hang otherwise"); + + // Verify we got both responses + responses.Should().HaveCountGreaterThanOrEqualTo(2, + "should receive CellsCreated + ExecutionCompleted"); + + responses[0].Status.Should().Be(SubmitMessageStatus.CellsCreated, + "first response should be CellsCreated"); + responses[0].Success.Should().BeTrue(); + + var lastResponse = responses.Last(); + lastResponse.Status.Should().Be(SubmitMessageStatus.ExecutionCompleted, + "final response should be ExecutionCompleted"); + lastResponse.Success.Should().BeTrue(); + lastResponse.ResponseText.Should().NotBeNullOrEmpty( + "ExecutionCompleted should include the agent's response text"); + + Output.WriteLine($"Delegation completion verified: {responses.Count} responses, final text length={lastResponse.ResponseText?.Length}"); + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/MeshWeaver.Hosting.Orleans.Test.csproj b/test/MeshWeaver.Hosting.Orleans.Test/MeshWeaver.Hosting.Orleans.Test.csproj index d064025fa..2ce209790 100644 --- a/test/MeshWeaver.Hosting.Orleans.Test/MeshWeaver.Hosting.Orleans.Test.csproj +++ b/test/MeshWeaver.Hosting.Orleans.Test/MeshWeaver.Hosting.Orleans.Test.csproj @@ -2,6 +2,9 @@ {bd553448-e2b5-4e44-8e91-fff0884a0b28} + + + PreserveNewest diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansApiTokenTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansApiTokenTest.cs new file mode 100644 index 000000000..6d2c04794 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansApiTokenTest.cs @@ -0,0 +1,99 @@ +using System; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Orleans integration test for API token creation and validation. +/// Uses standard CreateNodeRequest with nodeType=ApiToken — same satellite pattern +/// as Thread/Comment. The RLS validator maps ApiToken → Permission.Api. +/// +public class OrleansApiTokenTest(ITestOutputHelper output) : OrleansTestBase(output) +{ + protected override MessageHubConfiguration ConfigureClient(MessageHubConfiguration configuration) + { + configuration.TypeRegistry + .WithType(typeof(ValidateTokenRequest), nameof(ValidateTokenRequest)) + .WithType(typeof(ValidateTokenResponse), nameof(ValidateTokenResponse)); + return base.ConfigureClient(configuration); + } + + [Fact] + public async Task CreateApiToken_ViaStandardCreateNodeRequest() + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = await GetClientAsync(); + var meshAddress = ClientMesh.Address; + + // Generate token hash + var rawToken = $"mw_{Convert.ToHexString(RandomNumberGenerator.GetBytes(32)).ToLowerInvariant()}"; + var hash = ValidateTokenRequest.HashToken(rawToken); + var hashPrefix = hash[..12]; + + // Create token as satellite of User node — same pattern as Thread + var userId = "Roland"; + var tokenNode = new MeshNode(hashPrefix, $"User/{userId}/_Api") + { + Name = "Orleans Test Token", + NodeType = ApiTokenNodeType.NodeType, + MainNode = $"User/{userId}", + Content = new ApiToken + { + UserId = userId, + UserName = "Roland", + UserEmail = "rbuergi@systemorph.com", + TokenHash = hash, + Label = "Orleans Test Token", + CreatedAt = DateTimeOffset.UtcNow, + } + }; + + // Act — standard CreateNodeRequest (same as Thread creation) + var response = await client.AwaitResponse( + new CreateNodeRequest(tokenNode), + o => o.WithTarget(meshAddress), ct); + + response.Message.Success.Should().BeTrue(response.Message.Error); + response.Message.Node.Should().NotBeNull(); + response.Message.Node!.Path.Should().Be($"User/{userId}/_Api/{hashPrefix}"); + response.Message.Node.NodeType.Should().Be(ApiTokenNodeType.NodeType); + Output.WriteLine($"Token created at {response.Message.Node.Path}"); + } + + [Fact] + public async Task ValidateInvalidToken_Fails() + { + var ct = new CancellationTokenSource(15.Seconds()).Token; + var client = await GetClientAsync(); + + var fakeToken = "mw_0000000000000000000000000000000000000000000000000000000000000000"; + var hash = ValidateTokenRequest.HashToken(fakeToken); + var hashPrefix = hash[..12]; + + try + { + var response = await client.AwaitResponse( + new ValidateTokenRequest(fakeToken), + o => o.WithTarget(new Address("ApiToken", hashPrefix)), ct); + + // Either the response says failure, or the grain couldn't activate (token not found) + if (response.Message != null) + response.Message.Success.Should().BeFalse("invalid token should not validate"); + } + catch (Exception) + { + // Expected — grain activation fails because node doesn't exist + } + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansAutoExecuteTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansAutoExecuteTest.cs new file mode 100644 index 000000000..866473bff --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansAutoExecuteTest.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Orleans integration test: BuildThreadWithMessages + AutoExecutePendingMessage. +/// Creates a thread with pre-populated Messages + PendingUserMessage in one shot. +/// Verifies that: +/// 1. AutoExecutePendingMessage creates the child ThreadMessage nodes +/// 2. UpdateThreadMessageContent routes to the response grain +/// 3. Execution completes and response text is written +/// +/// This reproduces the production bug where UpdateThreadMessageContent +/// went to the thread grain instead of the response message grain +/// because the child nodes weren't created in persistence. +/// +[Collection(nameof(OrleansClusterCollection))] +public class OrleansAutoExecuteTest(SharedOrleansFixture fixture, ITestOutputHelper output) : TestBase(output) +{ + private async Task GetClientAsync([CallerMemberName] string? name = null) + => await fixture.GetClientAsync($"autoexec-{name}-{Guid.NewGuid():N}", "Roland"); + + private async Task GetHubContentAsync(IMessageHub client, string path, CancellationToken ct) where T : class + { + var nodeId = path.Contains('/') ? path[(path.LastIndexOf('/') + 1)..] : path; + var response = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address(path)), ct); + var node = response.Message.Data as MeshNode; + if (node == null && response.Message.Data is JsonElement je) + node = je.Deserialize(fixture.ClientMesh.JsonSerializerOptions); + if (node?.Content is T typed) return typed; + if (node?.Content is JsonElement contentJe) + return contentJe.Deserialize(fixture.ClientMesh.JsonSerializerOptions); + return null; + } + + /// + /// BuildThreadWithMessages creates thread + auto-executes. + /// Response cell must be created, receive UpdateThreadMessageContent, + /// and have final response text. Thread must end with IsExecuting=false. + /// + [Fact] + public async Task AutoExecute_CreatesResponseCell_And_CompletesExecution() + { + SharedOrleansFixture.SwappableFactory.SetInner(new AutoExecEchoChatClientFactory()); + try + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = await GetClientAsync(); + + // Build thread with pre-populated messages (auto-execute on activation) + var (threadNode, userMsgId, responseMsgId) = ThreadNodeType.BuildThreadWithMessages( + "User/Roland", "Hello Orleans auto-execute!", + createdBy: "Roland", agentName: "Orchestrator"); + var threadPath = threadNode.Path!; + Output.WriteLine($"Thread: {threadPath}, user={userMsgId}, response={responseMsgId}"); + + // Create the thread — AutoExecutePendingMessage should fire on grain activation + var createResponse = await client.AwaitResponse( + new CreateNodeRequest(threadNode), + o => o.WithTarget(new Address("User/Roland")), ct); + createResponse.Message.Success.Should().BeTrue(createResponse.Message.Error); + Output.WriteLine("Thread created, waiting for execution..."); + + // Poll for execution to complete + ThreadMessage? response = null; + var responsePath = $"{threadPath}/{responseMsgId}"; + for (var i = 0; i < 60; i++) + { + // Check thread state + var thread = await GetHubContentAsync(client, threadPath, ct); + if (thread is { IsExecuting: false, PendingUserMessage: null }) + { + Output.WriteLine($"Thread execution complete after {i * 500}ms"); + + // Verify response cell has content + response = await GetHubContentAsync(client, responsePath, ct); + break; + } + await Task.Delay(500, ct); + } + + response.Should().NotBeNull("response message must exist in persistence"); + response!.Text.Should().NotBeNullOrEmpty("agent should have written response text"); + Output.WriteLine($"Response: {response.Text[..Math.Min(100, response.Text.Length)]}"); + + // Verify user cell exists + var userMsg = await GetHubContentAsync(client, $"{threadPath}/{userMsgId}", ct); + userMsg.Should().NotBeNull("user message must exist in persistence"); + userMsg!.Text.Should().Be("Hello Orleans auto-execute!"); + userMsg.Role.Should().Be("user"); + + Output.WriteLine("PASSED"); + } + finally + { + SharedOrleansFixture.SwappableFactory.Reset(); + } + } + + /// + /// Verifies that UpdateThreadMessageContent reaches the response grain (not the thread grain). + /// The response cell should have text != "" and != "Allocating agent...". + /// + [Fact] + public async Task AutoExecute_UpdateThreadMessageContent_RoutesToResponseGrain() + { + SharedOrleansFixture.SwappableFactory.SetInner(new AutoExecEchoChatClientFactory()); + try + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = await GetClientAsync(); + + var (threadNode, _, responseMsgId) = ThreadNodeType.BuildThreadWithMessages( + "User/Roland", "Test routing to response grain", + createdBy: "Roland", agentName: "Orchestrator"); + var threadPath = threadNode.Path!; + var responsePath = $"{threadPath}/{responseMsgId}"; + + await client.AwaitResponse( + new CreateNodeRequest(threadNode), + o => o.WithTarget(new Address("User/Roland")), ct); + + // Poll for response cell to have final text (not empty, not "Allocating agent...") + for (var i = 0; i < 60; i++) + { + var msg = await GetHubContentAsync(client, responsePath, ct); + if (msg?.Text is { Length: > 0 } text && !text.StartsWith("Allocating") && !text.StartsWith("Loading") && !text.StartsWith("Generating")) + { + Output.WriteLine($"Response cell has final text after {i * 500}ms: {text[..Math.Min(80, text.Length)]}"); + return; // SUCCESS + } + await Task.Delay(500, ct); + } + throw new TimeoutException("UpdateThreadMessageContent never reached response cell with final text"); + } + finally + { + SharedOrleansFixture.SwappableFactory.Reset(); + } + } + + #region Echo LLM + + private class AutoExecEchoChatClient : IChatClient + { + public ChatClientMetadata Metadata => new("AutoExecEcho"); + public Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken ct = default) + => Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, $"Echo: {messages.Count()} messages"))); + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken ct = default) + { + yield return new ChatResponseUpdate(ChatRole.Assistant, $"Echo: {messages.Count()} messages received."); + await Task.Delay(10, ct); + } + + public object? GetService(Type serviceType, object? key = null) => serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } + } + + private class AutoExecEchoChatClientFactory : IChatClientFactory + { + public string Name => "AutoExecEchoFactory"; + public IReadOnlyList Models => ["echo-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => new(chatClient: new AutoExecEchoChatClient(), instructions: "Echo agent.", + name: config.Id, description: config.Description ?? "", + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); + } + + #endregion +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansChatHistoryTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansChatHistoryTest.cs new file mode 100644 index 000000000..694feb36d --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansChatHistoryTest.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Orleans integration test: cold-start scenario. +/// Pre-seeds a thread with 2 user + 2 assistant messages in persistence. +/// Submits a 3rd message and verifies the agent sees ALL 5 previous messages +/// via GetDataRequest + CombineLatest (not from cache or local workspace). +/// +[Collection(nameof(OrleansClusterCollection))] +public class OrleansChatHistoryTest(SharedOrleansFixture fixture, ITestOutputHelper output) : TestBase(output) +{ + private const string ThreadPath = "User/Roland/_Thread/history-cold-start"; + + private async Task GetClientAsync([CallerMemberName] string? name = null) + => await fixture.GetClientAsync($"hist-{name}-{Guid.NewGuid():N}", "Roland"); + + [Fact] + public async Task ColdStart_AgentSeesAllPreviousMessages() + { + // Swap to echo factory + SharedOrleansFixture.SwappableFactory.SetInner(new EchoChatClientFactory()); + try + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = await GetClientAsync(); + // Thread + 4 messages are pre-seeded in SharedOrleansFixture via AddMeshNodes. + // This simulates a cold start: grains not yet activated, data in persistence. + Output.WriteLine("Thread pre-seeded with 4 messages via AddMeshNodes"); + + // Submit and wait for response + // Post + collect TWO responses: CellsCreated then ExecutionCompleted + Output.WriteLine("Posting SubmitMessageRequest..."); + var completionTcs = new TaskCompletionSource(); + var delivery = client.Post(new SubmitMessageRequest + { + ThreadPath = ThreadPath, + UserMessageText = "Third question — can you see history?", + ContextPath = "User/Roland" + }, o => o.WithTarget(new Address(ThreadPath))); + delivery.Should().NotBeNull("Post should return a delivery"); + + var originalDelivery = (IMessageDelivery)delivery!; + void RegisterForCompletion() + { + _ = client.RegisterCallback(originalDelivery, resp => + { + if (resp is IMessageDelivery smr) + { + var msg = smr.Message; + Output.WriteLine($"Response: status={msg.Status}, success={msg.Success}, text={msg.ResponseText?[..Math.Min(60, msg.ResponseText?.Length ?? 0)]}"); + if (msg.Status == SubmitMessageStatus.ExecutionCompleted || + msg.Status == SubmitMessageStatus.ExecutionFailed) + completionTcs.TrySetResult(msg); + else + RegisterForCompletion(); // Re-register for completion response + } + return resp; + }); + } + RegisterForCompletion(); + + var completion = await completionTcs.Task.WaitAsync(TimeSpan.FromSeconds(20), ct); + Output.WriteLine($"Execution completed: success={completion.Success}, text={completion.ResponseText}"); + + completion.Success.Should().BeTrue("execution should succeed"); + // The agent MUST see 6 separate messages (4 pre-seeded history + 1 new input cell + 1 new user). + // If this fails, the ChatClientAgent is flattening conversation turns into a single prompt. + completion.ResponseText.Should().Contain("6 messages", + "agent must receive 6 separate ChatMessage objects, not a flattened prompt"); + } + finally + { + SharedOrleansFixture.SwappableFactory.Reset(); + } + } + + #region Echo LLM + + private class EchoChatClient : IChatClient + { + public ChatClientMetadata Metadata => new("EchoProvider"); + public Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken ct = default) + => Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, $"I received {messages.Count()} messages."))); + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken ct = default) + { + var msgList = messages.ToList(); + var summary = string.Join(" | ", msgList.Select((m, i) => + $"[{i}:{m.Role}:{(m.Text?.Length > 30 ? m.Text[..30] + "..." : m.Text)}]")); + yield return new ChatResponseUpdate(ChatRole.Assistant, + $"I received {msgList.Count} messages. {summary}"); + await Task.Delay(10, ct); + } + + public object? GetService(Type serviceType, object? key = null) => serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } + } + + private class EchoChatClientFactory : IChatClientFactory + { + public string Name => "EchoFactory"; + public IReadOnlyList Models => ["echo-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => new(chatClient: new EchoChatClient(), instructions: "Echo agent.", + name: config.Id, description: config.Description ?? "", + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); + } + + #endregion +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationFlowTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationFlowTest.cs new file mode 100644 index 000000000..66ac59ed5 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationFlowTest.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Hosting.Security; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// End-to-end test for delegation: the agent calls delegate_to_agent, +/// which creates a sub-thread and submits to it. Verifies that: +/// 1. Access context flows through the AI tool invocation chain +/// 2. CreateNode for the sub-thread succeeds (Thread permission) +/// 3. SubmitMessage to the sub-thread routes correctly +/// 4. The sub-thread executes and returns a result +/// +/// Uses a DelegationToolFakeChatClient that emits a FunctionCallContent +/// on the first call, triggering the delegation tool. +/// +public class OrleansDelegationFlowTest(ITestOutputHelper output) : TestBase(output) +{ + private TestCluster Cluster { get; set; } = null!; + private IMessageHub ClientMesh => Cluster.Client.ServiceProvider.GetRequiredService(); + + public override async ValueTask InitializeAsync() + { + await base.InitializeAsync(); + var builder = new TestClusterBuilder(); + builder.AddSiloBuilderConfigurator(); + builder.AddClientBuilderConfigurator(); + Cluster = builder.Build(); + await Cluster.DeployAsync(); + } + + public override async ValueTask DisposeAsync() + { + if (Cluster is not null) + await Cluster.DisposeAsync(); + await base.DisposeAsync(); + } + + private async Task GetClientAsync() + { + var client = ClientMesh.ServiceProvider.CreateMessageHub( + new Address("client", "delegation"), + config => + { + config.TypeRegistry.AddAITypes(); + return config.AddLayoutClient(); + }); + var accessService = client.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext + { + ObjectId = "Roland", + Name = "Roland Buergi", + Email = "rbuergi@systemorph.com" + }); + await Cluster.Client.ServiceProvider.GetRequiredService() + .RegisterStreamAsync(client.Address, client.DeliverMessage); + return client; + } + + private async Task CreateNodeAsync(IMessageHub client, MeshNode node, string targetAddress, CancellationToken ct) + { + var response = await client.AwaitResponse( + new CreateNodeRequest(node), + o => o.WithTarget(new Address(targetAddress)), ct); + response.Message.Success.Should().BeTrue(response.Message.Error); + return response.Message.Node!.Path!; + } + + /// + /// Full delegation flow: submit a message to a thread that triggers delegation. + /// The DelegationToolFakeChatClient emits a delegate_to_agent function call, + /// which creates a sub-thread, submits to it, and returns the result. + /// Verifies that access context flows through the entire chain. + /// + [Fact(Timeout = 60000)] + public async Task Delegation_CreatesSubThread_WithCorrectIdentity() + { + var ct = new CancellationTokenSource(50.Seconds()).Token; + var client = await GetClientAsync(); + + // Create a thread + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Delegation flow test", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + Output.WriteLine($"Thread: {threadPath}"); + + // Subscribe to thread messages + var workspace = client.GetWorkspace(); + var twoMessages = workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => + { + var node = nodes?.FirstOrDefault(n => n.Path == threadPath); + var content = node?.Content as MeshThread; + return content?.Messages ?? []; + }) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + // Submit message — this triggers the DelegationToolFakeChatClient which calls delegate_to_agent + Output.WriteLine("Posting SubmitMessageRequest (should trigger delegation)..."); + var submitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Please delegate this task", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); + Output.WriteLine("SubmitMessageRequest succeeded — cells created"); + + // Wait for message IDs + var msgIds = await twoMessages; + msgIds.Should().HaveCount(2); + Output.WriteLine($"Message IDs: [{string.Join(", ", msgIds)}]"); + + // Wait for execution to complete (agent streams + delegation + sub-thread) + ThreadMessage? responseMsg = null; + for (var i = 0; i < 60; i++) + { + var nodeId = msgIds[1]; + var resp = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address($"{threadPath}/{nodeId}")), ct); + var node = resp.Message.Data as MeshNode; + if (node == null && resp.Message.Data is JsonElement je) + node = je.Deserialize(ClientMesh.JsonSerializerOptions); + if (node?.Content is ThreadMessage tm) responseMsg = tm; + else if (node?.Content is JsonElement cje) + responseMsg = cje.Deserialize(ClientMesh.JsonSerializerOptions); + + if (responseMsg?.Text?.Contains("delegation", StringComparison.OrdinalIgnoreCase) == true + || responseMsg?.ToolCalls?.Count > 0) + break; + await Task.Delay(500, ct); + } + + responseMsg.Should().NotBeNull("response message should exist"); + Output.WriteLine($"Response: text='{responseMsg!.Text?[..Math.Min(100, responseMsg.Text?.Length ?? 0)]}', toolCalls={responseMsg.ToolCalls?.Count ?? 0}"); + + // The DelegationToolFakeChatClient triggers a delegation — verify it completed + // (either the tool call log has an entry, or the text mentions it) + var hasDelegation = responseMsg.ToolCalls?.Any(tc => tc.Name?.Contains("delegate") == true) == true + || responseMsg.Text?.Contains("delegat", StringComparison.OrdinalIgnoreCase) == true; + hasDelegation.Should().BeTrue("agent should have delegated via delegate_to_agent tool call"); + Output.WriteLine("Delegation flow verified!"); + } +} + +/// +/// Chat client that emits a delegate_to_agent function call on the first request, +/// then returns text on subsequent requests (after function result). +/// +internal class DelegationToolFakeChatClient : IChatClient +{ + private int _callCount; + public ChatClientMetadata Metadata => new("DelegatingFake"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken cancellationToken = default) + { + var call = Interlocked.Increment(ref _callCount); + if (call == 1 && options?.Tools?.Any(t => t.Name == "delegate_to_agent") == true) + { + // First call: emit a function call to delegate_to_agent + var functionCall = new FunctionCallContent("call_1", "delegate_to_agent", + new Dictionary + { + ["agentName"] = "Executor", + ["task"] = "Execute the user's request" + }); + var msg = new ChatMessage(ChatRole.Assistant, [functionCall]); + return Task.FromResult(new ChatResponse(msg)); + } + + // Subsequent calls: return text + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, "Delegation completed successfully."))); + } + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + var call = Interlocked.Increment(ref _callCount); + if (call == 1 && options?.Tools?.Any(t => t.Name == "delegate_to_agent") == true) + { + // First call: emit function call via streaming + yield return new ChatResponseUpdate + { + Role = ChatRole.Assistant, + Contents = [new FunctionCallContent("call_1", "delegate_to_agent", + new Dictionary + { + ["agentName"] = "Executor", + ["task"] = "Execute the user's request" + })] + }; + yield break; + } + + // Subsequent calls: stream text + foreach (var word in "Delegation completed successfully.".Split(' ')) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return new ChatResponseUpdate(ChatRole.Assistant, word + " "); + await Task.Delay(10, cancellationToken); + } + } + + public object? GetService(Type serviceType, object? serviceKey = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } +} + +/// +/// Factory that uses DelegationToolFakeChatClient for the default agent +/// and regular FakeChatClient for delegated agents (Executor). +/// +internal class DelegationToolFakeChatClientFactory : IChatClientFactory +{ + public string Name => "DelegationToolFakeFactory"; + public IReadOnlyList Models => ["fake-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + { + // Default agent gets the delegating client; others get plain text client + var isDefault = config.IsDefault || config.Id == "Navigator" || config.Id == "Planner"; + IChatClient chatClient = isDefault + ? new DelegationToolFakeChatClient() + : new FakeChatClient("Sub-thread response from delegated agent."); + + return new ChatClientAgent( + chatClient: chatClient, + instructions: config.Instructions ?? "Test assistant.", + name: config.Id, + description: config.Description ?? config.Id, + tools: [], + loggerFactory: null, + services: null); + } + + public Task CreateAgentAsync( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); +} + +public class DelegationSiloConfigurator : ISiloConfigurator, IHostConfigurator +{ + public void Configure(ISiloBuilder siloBuilder) + { + siloBuilder.ConfigureMeshWeaverServer() + .AddMemoryGrainStorageAsDefault(); + } + + public void Configure(IHostBuilder hostBuilder) + { + hostBuilder.UseOrleansMeshServer() + .ConfigurePortalMesh() + .AddRowLevelSecurity() + .AddMeshNodes( + new MeshNode("Roland", "User") { Name = "Roland", NodeType = "User" }) + .AddMeshNodes(PublicEditorAccess()) + .ConfigureServices(services => + services.AddSingleton(new DelegationToolFakeChatClientFactory())) + .ConfigureDefaultNodeHub(config => config.AddDefaultLayoutAreas()); + } + + private static MeshNode[] PublicEditorAccess() + { + var assignment = new AccessAssignment + { + AccessObject = "Public", + DisplayName = "Public", + Roles = [new RoleAssignment { Role = "Editor" }] + }; + return + [ + new("Public_Access", "User") + { + NodeType = "AccessAssignment", + Name = "Public Access", + Content = assignment, + MainNode = "User", + } + ]; + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationStartTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationStartTest.cs new file mode 100644 index 000000000..513687df9 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationStartTest.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Orleans test: delegation sub-thread starts execution automatically. +/// Simulates the exact delegation flow: +/// 1. Create user cell +/// 2. Create response cell +/// 3. Create thread with Messages + IsExecuting=true + PendingUserMessage +/// 4. WatchForExecution triggers → starts streaming → response cell gets text +/// +[Collection(nameof(OrleansClusterCollection))] +public class OrleansDelegationStartTest(SharedOrleansFixture fixture, ITestOutputHelper output) : TestBase(output) +{ + private async Task GetClientAsync([CallerMemberName] string? name = null) + => await fixture.GetClientAsync($"deleg-{name}-{Guid.NewGuid():N}", "Roland"); + + private async Task GetHubContentAsync(IMessageHub client, string path, CancellationToken ct) where T : class + { + var nodeId = path.Contains('/') ? path[(path.LastIndexOf('/') + 1)..] : path; + var response = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address(path)), ct); + var node = response.Message.Data as MeshNode; + if (node == null && response.Message.Data is JsonElement je) + node = je.Deserialize(fixture.ClientMesh.JsonSerializerOptions); + if (node?.Content is T typed) return typed; + if (node?.Content is JsonElement contentJe) + return contentJe.Deserialize(fixture.ClientMesh.JsonSerializerOptions); + return null; + } + + /// + /// Simulates delegation: create cells first, then thread with IsExecuting=true. + /// WatchForExecution should detect fresh execution and start streaming. + /// Response cell should have agent text when execution completes. + /// + [Fact] + public async Task Delegation_CreateCellsThenThread_ExecutionStartsAndCompletes() + { + SharedOrleansFixture.SwappableFactory.SetInner(new DelegationEchoChatClientFactory()); + try + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = await GetClientAsync(); + + // Create a parent thread first (delegations live under a response message) + var parentNode = ThreadNodeType.BuildThreadNode("User/Roland", "Parent for delegation test", "Roland"); + var parentResp = await client.AwaitResponse( + new CreateNodeRequest(parentNode), + o => o.WithTarget(new Address("User/Roland")), ct); + parentResp.Message.Success.Should().BeTrue(parentResp.Message.Error); + var parentPath = parentResp.Message.Node!.Path!; + Output.WriteLine($"Parent thread: {parentPath}"); + + // Simulate a response message on the parent (delegation lives under it) + var parentResponseId = Guid.NewGuid().ToString("N")[..8]; + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(parentResponseId, parentPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(parentPath)), ct); + var parentMsgPath = $"{parentPath}/{parentResponseId}"; + + // Now simulate delegation: create cells, then thread (exact ChatClientAgentFactory flow) + var (subThreadNode, userMsgId, responseMsgId) = ThreadNodeType.BuildThreadWithMessages( + parentMsgPath, "Delegation task: do something", createdBy: "Roland", agentName: "Worker"); + subThreadNode = subThreadNode with { MainNode = "User/Roland" }; + var subThreadPath = subThreadNode.Path!; + var responsePath = $"{subThreadPath}/{responseMsgId}"; + Output.WriteLine($"Sub-thread: {subThreadPath}, user={userMsgId}, response={responseMsgId}"); + + // Step 1: Create user cell + var userCellResp = await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, subThreadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage + { + Role = "user", Text = "Delegation task: do something", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.ExecutedInput, CreatedBy = "Roland" + } + }), o => o.WithTarget(new Address(subThreadPath)), ct); + Output.WriteLine($"User cell created: success={userCellResp.Message.Success}"); + + // Step 2: Create response cell + var responseCellResp = await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, subThreadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage + { + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse, AgentName = "Worker" + } + }), o => o.WithTarget(new Address(subThreadPath)), ct); + Output.WriteLine($"Response cell created: success={responseCellResp.Message.Success}"); + + // Step 3: Create thread with IsExecuting=true (triggers WatchForExecution) + var threadResp = await client.AwaitResponse( + new CreateNodeRequest(subThreadNode), + o => o.WithTarget(new Address(parentMsgPath)), ct); + threadResp.Message.Success.Should().BeTrue(threadResp.Message.Error); + Output.WriteLine("Sub-thread created — WatchForExecution should trigger"); + + // Step 4: Poll for execution to complete + for (var i = 0; i < 60; i++) + { + var thread = await GetHubContentAsync(client, subThreadPath, ct); + if (thread is { IsExecuting: false }) + { + Output.WriteLine($"Execution complete after {i * 500}ms"); + + var responseMsg = await GetHubContentAsync(client, responsePath, ct); + responseMsg.Should().NotBeNull("response cell must exist"); + responseMsg!.Text.Should().NotBeNullOrEmpty("agent must have written response"); + Output.WriteLine($"Response: {responseMsg.Text[..Math.Min(100, responseMsg.Text.Length)]}"); + Output.WriteLine("PASSED"); + return; + } + await Task.Delay(500, ct); + } + throw new TimeoutException("Delegation execution did not complete"); + } + finally + { + SharedOrleansFixture.SwappableFactory.Reset(); + } + } + + #region Echo LLM + + private class DelegationEchoChatClient : IChatClient + { + public ChatClientMetadata Metadata => new("DelegationEcho"); + public Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken ct = default) + => Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, $"Delegation echo: {messages.Count()} messages"))); + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken ct = default) + { + yield return new ChatResponseUpdate(ChatRole.Assistant, $"Delegation complete: processed {messages.Count()} messages."); + await Task.Delay(10, ct); + } + + public object? GetService(Type serviceType, object? key = null) => serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } + } + + private class DelegationEchoChatClientFactory : IChatClientFactory + { + public string Name => "DelegationEchoFactory"; + public IReadOnlyList Models => ["echo-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => new(chatClient: new DelegationEchoChatClient(), instructions: "Delegation echo.", + name: config.Id, description: config.Description ?? "", + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); + } + + #endregion +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationTest.cs new file mode 100644 index 000000000..63c660ee0 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansDelegationTest.cs @@ -0,0 +1,423 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Hosting.Security; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Delegation tests using the PRODUCTION ChatClientAgentFactory pipeline. +/// The test factory extends ChatClientAgentFactory so delegation tools, +/// MeshPlugin, and function calling middleware are all registered automatically. +/// This tests the real delegation flow: agent calls delegate_to_agent → +/// sub-thread created → sub-agent executes → result propagates back. +/// +/// +/// Delegation tests using per-class TestCluster because DelegationTestAgentFactory +/// extends ChatClientAgentFactory which needs the grain's IMessageHub at construction time. +/// The SwappableChatClientFactory pattern doesn't work for ChatClientAgentFactory subclasses. +/// +public class OrleansDelegationTest(ITestOutputHelper output) : TestBase(output) +{ + private TestCluster Cluster { get; set; } = null!; + private IMessageHub ClientMesh => Cluster.Client.ServiceProvider.GetRequiredService(); + + public override async ValueTask InitializeAsync() + { + await base.InitializeAsync(); + var builder = new TestClusterBuilder(); + builder.AddSiloBuilderConfigurator(); + builder.AddClientBuilderConfigurator(); + Cluster = builder.Build(); + await Cluster.DeployAsync(); + } + + public override async ValueTask DisposeAsync() + { + if (Cluster is not null) + await Cluster.DisposeAsync(); + await base.DisposeAsync(); + } + + private async Task GetClientAsync(string id = "delegation") + { + var client = ClientMesh.ServiceProvider.CreateMessageHub( + new Address("client", id), + config => + { + config.TypeRegistry.AddAITypes(); + return config.AddLayoutClient(); + }); + var accessService = client.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext + { + ObjectId = "Roland", + Name = "Roland Buergi", + Email = "rbuergi@systemorph.com" + }); + await Cluster.Client.ServiceProvider.GetRequiredService() + .RegisterStreamAsync(client.Address, client.DeliverMessage); + return client; + } + + private async Task CreateNodeAsync(IMessageHub client, MeshNode node, string targetAddress, CancellationToken ct) + { + var response = await client.AwaitResponse( + new CreateNodeRequest(node), + o => o.WithTarget(new Address(targetAddress)), ct); + response.Message.Success.Should().BeTrue(response.Message.Error); + return response.Message.Node!.Path!; + } + + private async Task GetHubContentAsync(IMessageHub client, string path, CancellationToken ct) where T : class + { + var nodeId = path.Contains('/') ? path[(path.LastIndexOf('/') + 1)..] : path; + var response = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address(path)), ct); + var node = response.Message.Data as MeshNode; + if (node == null && response.Message.Data is JsonElement je) + node = je.Deserialize(ClientMesh.JsonSerializerOptions); + if (node?.Content is T typed) return typed; + if (node?.Content is JsonElement contentJe) + return contentJe.Deserialize(ClientMesh.JsonSerializerOptions); + return null; + } + + /// + /// Full delegation flow using the production agent pipeline: + /// 1. Submit message to thread + /// 2. Default agent (Orchestrator) calls delegate_to_agent tool + /// 3. Sub-thread is created, sub-agent executes + /// 4. Tool calls appear on the response message with DelegationPath + /// 5. Parent completes with text + /// + [Fact(Timeout = 30000)] + public async Task Delegation_ToolCallsAppear_WithDelegationPath() + { + var ct = new CancellationTokenSource(25.Seconds()).Token; + var suffix = Guid.NewGuid().ToString("N")[..6]; + var client = await GetClientAsync($"del-{suffix}"); + var workspace = client.GetWorkspace(); + + // 1. Create thread + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Delegation tool call test", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + Output.WriteLine($"1. Thread: {threadPath}"); + + // 2. Subscribe to messages + var twoMessages = workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => + { + var node = nodes?.FirstOrDefault(n => n.Path == threadPath); + return (node?.Content as MeshThread)?.Messages ?? []; + }) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + // 3. Submit message — triggers delegation via production ChatClientAgentFactory + var submitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Please delegate this research task", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); + Output.WriteLine("2. Message submitted"); + + // 4. Wait for message cells + var msgIds = await twoMessages; + var responsePath = $"{threadPath}/{msgIds[1]}"; + Output.WriteLine($"3. Response message: {msgIds[1]}"); + + // 5. Subscribe to response message — wait for tool calls + Output.WriteLine("4. Waiting for tool calls on response..."); + var responseStream = workspace.GetRemoteStream(new Address(responsePath))!; + ThreadMessage? finalResponse = null; + + // Wait for execution to complete (text appears + all tool calls have results) + finalResponse = await responseStream + .Select(nodes => + { + var msg = nodes?.FirstOrDefault(n => n.Path == responsePath)?.Content as ThreadMessage; + if (msg != null && msg.ToolCalls.Count > 0) + Output.WriteLine($" [STREAM] text={msg.Text?.Length ?? 0}ch, toolCalls={msg.ToolCalls.Count}, delegations={msg.ToolCalls.Count(c => !string.IsNullOrEmpty(c.DelegationPath))}"); + return msg; + }) + .Where(m => !string.IsNullOrEmpty(m?.Text) && m!.ToolCalls.Count > 0 && m.ToolCalls.All(c => c.Result != null)) + .Timeout(20.Seconds()) + .FirstAsync() + .ToTask(ct); + + // 6. Verify tool calls + Output.WriteLine($"5. Response: text='{finalResponse!.Text?[..Math.Min(50, finalResponse.Text?.Length ?? 0)]}', toolCalls={finalResponse.ToolCalls.Count}"); + foreach (var tc in finalResponse.ToolCalls) + Output.WriteLine($" - {tc.Name}: success={tc.IsSuccess}, delegation={tc.DelegationPath ?? "(none)"}"); + + finalResponse.ToolCalls.Should().NotBeEmpty("agent should have called delegate_to_agent"); + var delegationCall = finalResponse.ToolCalls.FirstOrDefault(c => c.Name.Contains("delegate")); + delegationCall.Should().NotBeNull("should have a delegation tool call"); + delegationCall!.DelegationPath.Should().NotBeNullOrEmpty("delegation tool call should have DelegationPath"); + delegationCall.IsSuccess.Should().BeTrue("delegation should succeed"); + + Output.WriteLine($"6. DelegationPath: {delegationCall.DelegationPath}"); + + // 7. Verify sub-thread exists and completed + var subThreadPath = delegationCall.DelegationPath!; + var subThread = await GetHubContentAsync(client, subThreadPath, ct); + subThread.Should().NotBeNull("sub-thread should exist"); + subThread!.Messages.Should().HaveCount(2, "sub-thread should have user + response"); + Output.WriteLine($"7. Sub-thread: {subThreadPath}, messages={subThread.Messages.Count}"); + Output.WriteLine("8. PASSED — full delegation with DelegationPath"); + } + + /// + /// Resubmit after delegation: verifies no deadlock when resubmitting + /// a message that previously triggered delegation. + /// + [Fact(Timeout = 30000)] + public async Task Resubmit_AfterDelegation_DoesNotDeadlock() + { + var ct = new CancellationTokenSource(25.Seconds()).Token; + var suffix = Guid.NewGuid().ToString("N")[..6]; + var client = await GetClientAsync($"del-{suffix}"); + var workspace = client.GetWorkspace(); + + // 1. Create thread and submit + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Resubmit delegation test", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + + var twoMessages = workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => (nodes?.FirstOrDefault(n => n.Path == threadPath)?.Content as MeshThread)?.Messages ?? []) + .Where(ids => ids.Count >= 2) + .FirstAsync().ToTask(ct); + + await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Delegate something", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + + var msgIds = await twoMessages; + Output.WriteLine($"1. Initial messages: [{string.Join(", ", msgIds)}]"); + + // 2. Wait for execution to complete + await workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => (nodes?.FirstOrDefault(n => n.Path == threadPath)?.Content as MeshThread)) + .Where(t => t != null && !t.IsExecuting) + .Timeout(20.Seconds()) + .FirstAsync().ToTask(ct); + Output.WriteLine("2. Initial execution complete"); + + // 3. Resubmit + var resubmitted = workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => (nodes?.FirstOrDefault(n => n.Path == threadPath)?.Content as MeshThread)?.Messages ?? []) + .Where(ids => ids.Count >= 2 && !ids.SequenceEqual(msgIds)) + .Timeout(15.Seconds()) + .FirstAsync().ToTask(ct); + + client.Post(new ResubmitMessageRequest + { + ThreadPath = threadPath, + MessageId = msgIds[0], + UserMessageText = "Delegate something" + }, o => o.WithTarget(new Address(threadPath))); + + var newMsgIds = await resubmitted; + Output.WriteLine($"3. After resubmit: [{string.Join(", ", newMsgIds)}]"); + newMsgIds[0].Should().Be(msgIds[0], "user message preserved"); + newMsgIds[1].Should().NotBe(msgIds[1], "new response cell"); + Output.WriteLine("4. PASSED — resubmit after delegation, no deadlock"); + } +} + +/// +/// Test factory that extends ChatClientAgentFactory — gets delegation tools, +/// MeshPlugin, and middleware automatically from the production pipeline. +/// Only overrides CreateChatClient to return a fake. +/// +internal class DelegationTestAgentFactory(IMessageHub hub) : ChatClientAgentFactory(hub) +{ + public override string Name => "DelegationTestFactory"; + public override IReadOnlyList Models => ["test-model"]; + public override int Order => 0; + + protected override IChatClient CreateChatClient(AgentConfiguration agentConfig) + { + // Default agent (Orchestrator) delegates; sub-agents return text + var isDefault = agentConfig.IsDefault || agentConfig.Id is "Orchestrator" or "Planner"; + return isDefault + ? new DelegatingTestChatClient() + : new SimpleTestChatClient("Sub-thread completed the research task successfully."); + } +} + +/// +/// Chat client that emits delegate_to_agent on first call, text after. +/// +internal class DelegatingTestChatClient : IChatClient +{ + public ChatClientMetadata Metadata => new("DelegatingTest"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken cancellationToken = default) + { + var hasFunctionResult = messages.Any(m => m.Contents.OfType().Any()); + if (hasFunctionResult) + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, "Delegation completed. Task done."))); + + // Check if delegate_to_agent tool is available + if (options?.Tools?.Any(t => t.Name == "delegate_to_agent") == true) + { + var call = new FunctionCallContent("del-1", "delegate_to_agent", + new Dictionary + { + ["agentName"] = "Worker", + ["task"] = "Research the topic and report findings" + }); + return Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, [call]))); + } + + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, "No delegation tool available."))); + } + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + var response = await GetResponseAsync(messages, options, cancellationToken); + var msg = response.Messages.First(); + var functionCalls = msg.Contents.OfType().ToList(); + if (functionCalls.Count > 0) + { + yield return new ChatResponseUpdate + { + Role = ChatRole.Assistant, + Contents = [..functionCalls] + }; + yield break; + } + foreach (var word in (msg.Text ?? "Done.").Split(' ')) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return new ChatResponseUpdate(ChatRole.Assistant, word + " "); + await Task.Delay(10, cancellationToken); + } + } + + public object? GetService(Type serviceType, object? serviceKey = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } +} + +/// +/// Simple chat client that returns canned text. +/// +internal class SimpleTestChatClient(string response) : IChatClient +{ + public ChatClientMetadata Metadata => new("SimpleTest"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken cancellationToken = default) + => Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, response))); + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + foreach (var word in response.Split(' ')) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return new ChatResponseUpdate(ChatRole.Assistant, word + " "); + await Task.Delay(10, cancellationToken); + } + } + + public object? GetService(Type serviceType, object? serviceKey = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } +} + +/// +/// Production-like silo with DelegationTestAgentFactory extending ChatClientAgentFactory. +/// This gives delegation tools, MeshPlugin, and function calling middleware. +/// +public class DelegationProductionSiloConfigurator : ISiloConfigurator, IHostConfigurator +{ + public void Configure(ISiloBuilder siloBuilder) + { + siloBuilder.ConfigureMeshWeaverServer() + .AddMemoryGrainStorageAsDefault(); + } + + public void Configure(IHostBuilder hostBuilder) + { + hostBuilder.UseOrleansMeshServer() + .ConfigurePortalMesh() + .AddRowLevelSecurity() + .AddMeshNodes( + new MeshNode("Roland", "User") { Name = "Roland", NodeType = "User" }) + .AddMeshNodes(PublicEditorAccess()) + .ConfigureServices(services => + services.AddSingleton()) + .ConfigureDefaultNodeHub(config => config.AddDefaultLayoutAreas()); + } + + private static MeshNode[] PublicEditorAccess() + { + var assignment = new AccessAssignment + { + AccessObject = "Public", + DisplayName = "Public", + Roles = [new RoleAssignment { Role = "Editor" }] + }; + return + [ + new("Public_Access", "User") + { + NodeType = "AccessAssignment", + Name = "Public Access", + Content = assignment, + MainNode = "User", + } + ]; + } +} + diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansMeshChangeFeedTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansMeshChangeFeedTest.cs new file mode 100644 index 000000000..e36cdd22f --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansMeshChangeFeedTest.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Hosting.Security; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Tests that the MeshChangeFeed propagates across Orleans silos +/// and that path resolver cache is invalidated correctly. +/// Uses the shared test cluster. +/// +[Collection(nameof(OrleansClusterCollection))] +public class OrleansMeshChangeFeedTest(SharedOrleansFixture fixture, ITestOutputHelper output) : TestBase(output) +{ + private IMessageHub ClientMesh => fixture.ClientMesh; + + private async Task GetClientAsync(string id) + => await fixture.GetClientAsync(id); + + private async Task CreateNodeAsync(IMessageHub client, MeshNode node, string targetAddress, CancellationToken ct) + { + Output.WriteLine($"CreateNodeRequest: id={node.Id}, target={targetAddress}"); + var response = await client.AwaitResponse( + new CreateNodeRequest(node), + o => o.WithTarget(new Address(targetAddress)), ct); + Output.WriteLine($"CreateNodeResponse: success={response.Message.Success}, path={response.Message.Node?.Path ?? "(null)"}"); + response.Message.Success.Should().BeTrue(response.Message.Error); + return response.Message.Node!.Path!; + } + + /// + /// Create a node, then immediately resolve its path. + /// The path resolver cache must be invalidated by the Created event + /// so the new node is found (not a stale partial match to parent). + /// + [Fact(Timeout = 30000)] + public async Task CreateNode_PathResolverFindsItImmediately() + { + var ct = new CancellationTokenSource(25.Seconds()).Token; + var suffix = Guid.NewGuid().ToString("N")[..6]; + var client = await GetClientAsync($"cfeed-{suffix}"); + + // Create parent + var parentNode = new MeshNode($"cfeed-parent-{suffix}", "User/Roland") + { + Name = "Change Feed Parent", + NodeType = "Markdown" + }; + var parentPath = await CreateNodeAsync(client, parentNode, "User/Roland", ct); + Output.WriteLine($"Parent: {parentPath}"); + + // Create child + var childNode = new MeshNode($"cfeed-child-{suffix}", parentPath) + { + Name = "Change Feed Child", + NodeType = "Markdown" + }; + var childPath = await CreateNodeAsync(client, childNode, "User/Roland", ct); + Output.WriteLine($"Child: {childPath}"); + + // Verify: child is reachable via message routing (GetDataRequest) + var childNodeId = $"cfeed-child-{suffix}"; + var getResponse = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), childNodeId)), + o => o.WithTarget(new Address(childPath)), ct); + var data = getResponse.Message.Data as MeshNode; + if (data == null && getResponse.Message.Data is JsonElement je) + data = je.Deserialize(ClientMesh.JsonSerializerOptions); + data.Should().NotBeNull("child node should be reachable via routing"); + data!.Path.Should().Be(childPath); + Output.WriteLine("PASSED — CreateNode immediately routable"); + } + + /// + /// The original production bug: delegation creates a sub-thread, + /// then SubmitMessageRequest must route to it correctly. + /// The path resolver cache must not serve a stale partial match. + /// + [Fact(Timeout = 30000)] + public async Task DelegationSubThread_RoutesAfterCreate() + { + var ct = new CancellationTokenSource(25.Seconds()).Token; + var suffix = Guid.NewGuid().ToString("N")[..6]; + var client = await GetClientAsync($"cfeed-del-{suffix}"); + + // Create thread + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "ChangeFeed routing test", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + Output.WriteLine($"Thread: {threadPath}"); + + // Submit message (creates user + response cells) + var workspace = client.GetWorkspace(); + var twoMessages = workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => + { + var node = nodes?.Cast().FirstOrDefault(n => n.Path == threadPath); + return (node?.Content as MeshThread)?.Messages ?? []; + }) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + var submitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Test routing", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); + + var msgIds = await twoMessages; + msgIds.Should().HaveCount(2); + Output.WriteLine($"Messages: [{string.Join(", ", msgIds)}]"); + + // Create sub-thread under the response message (same as delegation does) + var responseMsgId = msgIds[1]; + var parentMsgPath = $"{threadPath}/{responseMsgId}"; + var subThreadId = $"sub-{suffix}"; + + var subThreadNode = new MeshNode(subThreadId, parentMsgPath) + { + Name = "Sub-thread routing test", + NodeType = ThreadNodeType.NodeType, + MainNode = "User/Roland", + Content = new MeshThread { CreatedBy = "Roland" } + }; + var subThreadPath = await CreateNodeAsync(client, subThreadNode, threadPath, ct); + Output.WriteLine($"Sub-thread created: {subThreadPath}"); + + // NOW submit to the sub-thread — this is where routing failed before + // (stale cache sent SubmitMessageRequest to the parent message grain) + var subSubmitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = subThreadPath, + UserMessageText = "Hello sub-thread", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(subThreadPath)), ct); + + subSubmitResponse.Message.Success.Should().BeTrue( + $"Sub-thread SubmitMessage should succeed but got: {subSubmitResponse.Message.Error}"); + Output.WriteLine("PASSED — sub-thread SubmitMessage routed correctly"); + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansNodeChangePropagationTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansNodeChangePropagationTest.cs new file mode 100644 index 000000000..e59971fa2 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansNodeChangePropagationTest.cs @@ -0,0 +1,592 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Hosting.Security; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// End-to-end Orleans test for NodeChangeEntry propagation through delegation chains. +/// +/// Exercises the FULL production flow: +/// 1. Client creates a thread (like ThreadChatView.SendMessageAsync) +/// 2. Client submits a message (SubmitMessageRequest → thread grain) +/// 3. Thread grain creates user + response cells via Observable +/// 4. Execution starts on _Exec hosted hub (streaming loop via InvokeAsync) +/// 5. Top-level agent calls Create tool (MeshPlugin) → NodeChangeEntry generated +/// 6. Top-level agent delegates to sub-agent → sub-thread created, SubmitMessage posted +/// 7. Sub-agent calls Patch tool → NodeChangeEntry generated in sub-thread +/// 8. Sub-thread completes → SubmitMessageResponse.UpdatedNodes propagates up +/// 9. Parent merges node changes via ForwardNodeChange → aggregated with min/max versions +/// 10. Parent completes → final NodeChangeEntry list on response message +/// +/// This test specifically validates: +/// - No deadlocks in the delegation chain (execution hub, TCS resolution, callbacks) +/// - Access context propagation through all hops +/// - NodeChangeEntry aggregation across delegation boundaries +/// - Correct routing of deeply nested sub-thread paths in Orleans +/// +public class OrleansNodeChangePropagationTest(ITestOutputHelper output) : TestBase(output) +{ + private TestCluster Cluster { get; set; } = null!; + private IMessageHub ClientMesh => Cluster.Client.ServiceProvider.GetRequiredService(); + + public override async ValueTask InitializeAsync() + { + await base.InitializeAsync(); + var builder = new TestClusterBuilder(); + builder.AddSiloBuilderConfigurator(); + builder.AddClientBuilderConfigurator(); + Cluster = builder.Build(); + await Cluster.DeployAsync(); + } + + public override async ValueTask DisposeAsync() + { + if (Cluster is not null) + await Cluster.DisposeAsync(); + await base.DisposeAsync(); + } + + /// + /// Creates a client hub with user identity — same as the Blazor portal does + /// when a user opens a chat panel. + /// + private async Task GetClientAsync() + { + var client = ClientMesh.ServiceProvider.CreateMessageHub( + new Address("client", "nodechange"), + config => + { + config.TypeRegistry.AddAITypes(); + return config.AddLayoutClient(); + }); + // Simulate Blazor CircuitContext — user identity for access control + var accessService = client.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext + { + ObjectId = "Roland", + Name = "Roland Buergi", + Email = "rbuergi@systemorph.com" + }); + await Cluster.Client.ServiceProvider.GetRequiredService() + .RegisterStreamAsync(client.Address, client.DeliverMessage); + return client; + } + + private async Task CreateNodeAsync(IMessageHub client, MeshNode node, string targetAddress, CancellationToken ct) + { + Output.WriteLine($"CreateNodeRequest: id={node.Id}, path={node.Path}, target={targetAddress}"); + var response = await client.AwaitResponse( + new CreateNodeRequest(node), + o => o.WithTarget(new Address(targetAddress)), ct); + Output.WriteLine($"CreateNodeResponse: success={response.Message.Success}, error={response.Message.Error ?? "(none)"}, path={response.Message.Node?.Path ?? "(null)"}, nodeType={response.Message.Node?.NodeType ?? "(null)"}"); + response.Message.Success.Should().BeTrue(response.Message.Error); + return response.Message.Node!.Path!; + } + + private IObservable> ObserveThreadMessages(IMessageHub client, string threadPath) + { + var workspace = client.GetWorkspace(); + return workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => + { + var node = nodes?.FirstOrDefault(n => n.Path == threadPath); + var content = node?.Content as MeshThread; + var ids = content?.Messages ?? []; + Output.WriteLine($"[Stream] Thread {threadPath}: {ids.Count} message IDs"); + return (IReadOnlyList)ids; + }); + } + + private async Task GetHubContentAsync(IMessageHub client, string path, CancellationToken ct) where T : class + { + var nodeId = path.Contains('/') ? path[(path.LastIndexOf('/') + 1)..] : path; + var response = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address(path)), ct); + var node = response.Message.Data as MeshNode; + if (node == null && response.Message.Data is JsonElement je) + node = je.Deserialize(ClientMesh.JsonSerializerOptions); + if (node?.Content is T typed) return typed; + if (node?.Content is JsonElement contentJe) + return contentJe.Deserialize(ClientMesh.JsonSerializerOptions); + return null; + } + + /// + /// Full chain: top agent calls Create → delegates → sub-agent calls Patch → NodeChangeEntry propagates. + /// Tests for deadlocks: the execution hub (InvokeAsync) blocks during streaming; + /// delegation TCS resolution must not require the blocked scheduler. + /// + [Fact(Timeout = 60000)] + public async Task Delegation_NodeChanges_PropagateFromSubThread() + { + var ct = new CancellationTokenSource(50.Seconds()).Token; + var client = await GetClientAsync(); + + // 1. Create thread — exactly like ThreadChatView.SendMessageAsync does + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "NodeChange propagation test", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + Output.WriteLine($"Thread created: {threadPath}"); + + // 2. Subscribe to messages (like ThreadChatView data-binding) + var twoMessages = ObserveThreadMessages(client, threadPath) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + // 3. Submit message — triggers the ToolCallDelegatingChatClient which: + // Turn 1: calls Create (creates a Markdown node) + // Turn 2: calls delegate_to_agent (Executor) + // Turn 3: returns summary text after delegation completes + Output.WriteLine("Posting SubmitMessageRequest (Create + Delegate chain)..."); + var submitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Create a doc and delegate updates to Executor", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); + Output.WriteLine("SubmitMessageRequest succeeded — cells created"); + + // 4. Wait for message IDs + var msgIds = await twoMessages; + msgIds.Should().HaveCount(2); + Output.WriteLine($"Message IDs: [{string.Join(", ", msgIds)}]"); + + // 5. Wait for execution to complete — poll response message + // If the delegation chain deadlocks, this times out. + var responsePath = $"{threadPath}/{msgIds[1]}"; + ThreadMessage? responseMsg = null; + for (var i = 0; i < 60; i++) + { + responseMsg = await GetHubContentAsync(client, responsePath, ct); + // Wait until we have tool calls AND text (execution complete) + if (responseMsg?.ToolCalls is { Count: >= 2 } && !string.IsNullOrEmpty(responseMsg.Text)) + { + Output.WriteLine($" Poll {i}: text='{responseMsg.Text?[..Math.Min(80, responseMsg.Text.Length)]}', toolCalls={responseMsg.ToolCalls.Count}, updatedNodes={responseMsg.UpdatedNodes.Count}"); + break; + } + Output.WriteLine($" Poll {i}: text len={responseMsg?.Text?.Length ?? 0}, toolCalls={responseMsg?.ToolCalls?.Count ?? 0}"); + await Task.Delay(500, ct); + } + + // 6. Verify response message has tool calls + responseMsg.Should().NotBeNull("response message should exist after execution"); + responseMsg!.ToolCalls.Should().NotBeNullOrEmpty("agent should have made tool calls"); + + var createCall = responseMsg.ToolCalls.FirstOrDefault(t => t.Name == "Create"); + createCall.Should().NotBeNull("agent should have called Create tool"); + createCall!.IsSuccess.Should().BeTrue("Create tool should succeed"); + Output.WriteLine($"Create tool call: success={createCall.IsSuccess}, args={createCall.Arguments?[..Math.Min(60, createCall.Arguments?.Length ?? 0)]}"); + + var delegateCall = responseMsg.ToolCalls.FirstOrDefault(t => t.Name?.Contains("delegate") == true); + delegateCall.Should().NotBeNull("agent should have called delegate_to_agent"); + delegateCall!.DelegationPath.Should().NotBeNullOrEmpty("delegation should have a sub-thread path"); + Output.WriteLine($"Delegation: path={delegateCall.DelegationPath}, success={delegateCall.IsSuccess}"); + + // 7. Verify the Markdown node was created by the Create tool + var meshService = Cluster.Client.ServiceProvider.GetRequiredService(); + var createdNodes = await meshService + .QueryAsync("path:User/Roland/test-doc-nodechange", ct: ct) + .ToListAsync(ct); + createdNodes.Should().ContainSingle("Create tool should have created the Markdown node"); + Output.WriteLine($"Created node: {createdNodes[0].Path}, name={createdNodes[0].Name}"); + + // 8. Verify sub-thread exists and completed + var subThreadPath = delegateCall.DelegationPath!; + var subThread = await GetHubContentAsync(client, subThreadPath, ct); + subThread.Should().NotBeNull("sub-thread should exist"); + subThread!.Messages.Should().HaveCount(2, "sub-thread should have user + response messages"); + Output.WriteLine($"Sub-thread: {subThreadPath}, messages={subThread.Messages.Count}"); + + // 9. Verify sub-thread response has Patch tool call + var subResponsePath = $"{subThreadPath}/{subThread.Messages[1]}"; + ThreadMessage? subResponseMsg = null; + for (var i = 0; i < 30; i++) + { + subResponseMsg = await GetHubContentAsync(client, subResponsePath, ct); + if (subResponseMsg?.ToolCalls is { Count: > 0 }) break; + await Task.Delay(200, ct); + } + subResponseMsg.Should().NotBeNull("sub-thread response should exist"); + var patchCall = subResponseMsg!.ToolCalls.FirstOrDefault(t => t.Name == "Patch"); + patchCall.Should().NotBeNull("sub-agent should have called Patch tool"); + Output.WriteLine($"Sub-thread Patch: success={patchCall!.IsSuccess}, args={patchCall.Arguments?[..Math.Min(60, patchCall.Arguments?.Length ?? 0)]}"); + + // 10. Verify NodeChangeEntry propagated to parent response + responseMsg.UpdatedNodes.Should().NotBeNullOrEmpty( + "parent response should have aggregated UpdatedNodes from both Create and sub-thread Patch"); + Output.WriteLine($"UpdatedNodes on parent response: {responseMsg.UpdatedNodes.Count} entries"); + foreach (var entry in responseMsg.UpdatedNodes) + Output.WriteLine($" {entry.Operation}: {entry.Path} v{entry.VersionBefore}→v{entry.VersionAfter}"); + + // The same node (test-doc-nodechange) was Created by parent and Patched by sub-thread. + // Aggregation should give: min(VersionBefore), max(VersionAfter) + var docChanges = responseMsg.UpdatedNodes.Where(e => e.Path.Contains("test-doc-nodechange")).ToList(); + docChanges.Should().ContainSingle( + "changes to same node should be aggregated into one entry"); + var docChange = docChanges[0]; + docChange.VersionAfter.Should().BeGreaterThan(docChange.VersionBefore ?? 0, + "aggregated version should show progression from create to patch"); + Output.WriteLine($"Aggregated: {docChange.Path} {docChange.Operation} v{docChange.VersionBefore}→v{docChange.VersionAfter}"); + } + + /// + /// Resubmit test: after execution completes, click "Resubmit" (ArrowSync). + /// The HandleResubmitMessage handler must not deadlock — it uses + /// meshService.CreateNode (Observable) + workspace.UpdateMeshNode (non-blocking). + /// + [Fact(Timeout = 60000)] + public async Task Resubmit_AfterExecution_DoesNotDeadlock() + { + var ct = new CancellationTokenSource(50.Seconds()).Token; + var client = await GetClientAsync(); + + // 1. Create and execute a thread + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Resubmit deadlock test", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + + var twoMessages = ObserveThreadMessages(client, threadPath) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "First message", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + + var msgIds = await twoMessages; + Output.WriteLine($"Initial messages: [{string.Join(", ", msgIds)}]"); + + // Wait for execution to complete + for (var i = 0; i < 30; i++) + { + var thread = await GetHubContentAsync(client, threadPath, ct); + if (thread?.IsExecuting == false) break; + await Task.Delay(500, ct); + } + Output.WriteLine("Initial execution complete"); + + // 2. Resubmit — sends ResubmitMessageRequest to the thread grain. + // This was the original deadlock: the handler subscribed to workspace streams. + // Now uses Observable + workspace.UpdateMeshNode. + // Resubmit keeps user message (index 0) + adds new response = 2 messages. + // But the IDs change (old response removed, new one added). + // Watch for the stream to show a DIFFERENT set of IDs than the initial ones. + var resubmittedMessages = ObserveThreadMessages(client, threadPath) + .Where(ids => ids.Count >= 2 && !ids.SequenceEqual(msgIds)) + .FirstAsync() + .ToTask(ct); + + Output.WriteLine("Posting ResubmitMessageRequest..."); + var resubmitDelivery = client.Post(new ResubmitMessageRequest + { + ThreadPath = threadPath, + MessageId = msgIds[0], + UserMessageText = "Resubmitted message" + }, o => o.WithTarget(new Address(threadPath))); + Output.WriteLine($"ResubmitMessageRequest delivery: {resubmitDelivery != null}"); + + // 3. Wait for message IDs to change — if deadlocked, this times out + var newMsgIds = await resubmittedMessages; + newMsgIds.Should().HaveCount(2, + "resubmit should keep user message and replace response"); + newMsgIds[0].Should().Be(msgIds[0], "user message should be preserved"); + newMsgIds[1].Should().NotBe(msgIds[1], "response should be a new cell"); + Output.WriteLine($"After resubmit: [{string.Join(", ", newMsgIds)}]"); + + // 4. Resubmit succeeded — messages changed, no deadlock. + // The execution will complete asynchronously (streaming on _Exec hub). + Output.WriteLine("Resubmit completed — messages updated, no deadlock!"); + } +} + +/// +/// Chat client that exercises the full tool-calling and delegation chain: +/// - Turn 1: calls Create tool (creates a Markdown node) +/// - Turn 2 (after Create result): calls delegate_to_agent (Executor) +/// - Turn 3 (after delegation result): returns summary text +/// +internal class ToolCallDelegatingChatClient : IChatClient +{ + private int _callCount; + public ChatClientMetadata Metadata => new("ToolCallDelegating"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken cancellationToken = default) + { + var call = Interlocked.Increment(ref _callCount); + var hasFunctionResult = messages.Any(m => m.Contents.OfType().Any()); + var hasCreateResult = messages.Any(m => m.Contents.OfType() + .Any(f => f.CallId == "call_create")); + var hasDelegateResult = messages.Any(m => m.Contents.OfType() + .Any(f => f.CallId == "call_delegate")); + + // After delegation completes: return summary text + if (hasDelegateResult) + { + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, + "Created the document and delegated updates. All node changes should propagate."))); + } + + // After Create tool returns: call delegate_to_agent + if (hasCreateResult && options?.Tools?.Any(t => t.Name == "delegate_to_agent") == true) + { + var delegateCall = new FunctionCallContent("call_delegate", "delegate_to_agent", + new Dictionary + { + ["agentName"] = "Worker", + ["task"] = "Patch the node at User/Roland/test-doc-nodechange: set name to 'Updated by sub-agent'" + }); + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, [delegateCall]))); + } + + // First call: Create a Markdown node via MeshPlugin + if (options?.Tools?.Any(t => t.Name == "Create") == true) + { + var nodeJson = JsonSerializer.Serialize(new + { + id = "test-doc-nodechange", + @namespace = "User/Roland", + nodeType = "Markdown", + name = "Test Doc for NodeChange", + content = "# Initial Content" + }); + var createCall = new FunctionCallContent("call_create", "Create", + new Dictionary { ["node"] = nodeJson }); + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, [createCall]))); + } + + // Fallback + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, "Done."))); + } + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + // Delegate to non-streaming for simplicity — the framework handles both + var response = await GetResponseAsync(messages, options, cancellationToken); + var msg = response.Messages.First(); + var functionCalls = msg.Contents.OfType().ToList(); + if (functionCalls.Count > 0) + { + yield return new ChatResponseUpdate + { + Role = ChatRole.Assistant, + Contents = [..functionCalls] + }; + yield break; + } + // Stream text word by word + foreach (var word in (msg.Text ?? "Done.").Split(' ')) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return new ChatResponseUpdate(ChatRole.Assistant, word + " "); + await Task.Delay(10, cancellationToken); + } + } + + public object? GetService(Type serviceType, object? serviceKey = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } +} + +/// +/// Sub-agent chat client (Worker/Executor) that calls Patch tool: +/// - Turn 1: calls Patch on the node created by the parent +/// - Turn 2 (after Patch result): returns text +/// +internal class PatchToolChatClient : IChatClient +{ + private int _callCount; + public ChatClientMetadata Metadata => new("PatchTool"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken cancellationToken = default) + { + var call = Interlocked.Increment(ref _callCount); + var hasFunctionResult = messages.Any(m => m.Contents.OfType().Any()); + + if (hasFunctionResult) + { + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, + "Patched the document successfully. Node changes tracked."))); + } + + // First call: Patch the node + if (options?.Tools?.Any(t => t.Name == "Patch") == true) + { + var fieldsJson = JsonSerializer.Serialize(new { name = "Updated by sub-agent" }); + var patchCall = new FunctionCallContent("call_patch", "Patch", + new Dictionary + { + ["path"] = "User/Roland/test-doc-nodechange", + ["fields"] = fieldsJson + }); + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, [patchCall]))); + } + + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, "No Patch tool available."))); + } + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + var response = await GetResponseAsync(messages, options, cancellationToken); + var msg = response.Messages.First(); + var functionCalls = msg.Contents.OfType().ToList(); + if (functionCalls.Count > 0) + { + yield return new ChatResponseUpdate + { + Role = ChatRole.Assistant, + Contents = [..functionCalls] + }; + yield break; + } + foreach (var word in (msg.Text ?? "Done.").Split(' ')) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return new ChatResponseUpdate(ChatRole.Assistant, word + " "); + await Task.Delay(10, cancellationToken); + } + } + + public object? GetService(Type serviceType, object? serviceKey = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } +} + +/// +/// Factory: top-level agents (Navigator/Planner/Orchestrator) get ToolCallDelegatingChatClient; +/// sub-agents (Worker/Executor/Coder) get PatchToolChatClient. +/// +internal class NodeChangeTestChatClientFactory : IChatClientFactory +{ + public string Name => "NodeChangeTestFactory"; + public IReadOnlyList Models => ["fake-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + { + var isTopLevel = config.IsDefault || config.Id is "Navigator" or "Planner" or "Orchestrator"; + IChatClient chatClient = isTopLevel + ? new ToolCallDelegatingChatClient() + : new PatchToolChatClient(); + + return new ChatClientAgent( + chatClient: chatClient, + instructions: config.Instructions ?? "Test assistant with tools.", + name: config.Id, + description: config.Description ?? config.Id, + tools: [], // Tools added by ChatClientAgentFactory + loggerFactory: null, + services: null); + } + + public Task CreateAgentAsync( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); +} + +/// +/// Silo configurator: production-like setup with Graph + AI + RLS + NodeChangeTestChatClientFactory. +/// +public class NodeChangePropagationSiloConfigurator : ISiloConfigurator, IHostConfigurator +{ + public void Configure(ISiloBuilder siloBuilder) + { + siloBuilder.ConfigureMeshWeaverServer() + .AddMemoryGrainStorageAsDefault(); + } + + public void Configure(IHostBuilder hostBuilder) + { + hostBuilder.UseOrleansMeshServer() + .ConfigurePortalMesh() + .AddGraph() + .AddAI() + .AddRowLevelSecurity() + .AddMeshNodes( + new MeshNode("Roland", "User") { Name = "Roland", NodeType = "User" }) + .AddMeshNodes(PublicEditorAccess()) + .ConfigureServices(services => + services.AddSingleton(new NodeChangeTestChatClientFactory())) + .ConfigureDefaultNodeHub(config => config.AddDefaultLayoutAreas()); + } + + private static MeshNode[] PublicEditorAccess() + { + var assignment = new AccessAssignment + { + AccessObject = "Public", + DisplayName = "Public", + Roles = [new RoleAssignment { Role = "Editor" }] + }; + return + [ + new("Public_Access", "User") + { + NodeType = "AccessAssignment", + Name = "Public Access", + Content = assignment, + MainNode = "User", + } + ]; + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansPortalFlowTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansPortalFlowTest.cs new file mode 100644 index 000000000..bb3b7c27b --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansPortalFlowTest.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Orleans integration: exact portal flow. +/// 1. Create thread (BuildThreadNode) +/// 2. Create user cell → verify +/// 3. Create response cell → verify +/// 4. SubmitMessageRequest (state update only) → verify +/// 5. WatchForExecution triggers execution +/// 6. Response cell gets agent text +/// +[Collection(nameof(OrleansClusterCollection))] +public class OrleansPortalFlowTest(SharedOrleansFixture fixture, ITestOutputHelper output) : TestBase(output) +{ + private async Task GetClientAsync([CallerMemberName] string? name = null) + => await fixture.GetClientAsync($"portal-{name}-{Guid.NewGuid():N}", "Roland"); + + private async Task GetHubContentAsync(IMessageHub client, string path, CancellationToken ct) where T : class + { + var nodeId = path.Contains('/') ? path[(path.LastIndexOf('/') + 1)..] : path; + var response = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address(path)), ct); + var node = response.Message.Data as MeshNode; + if (node == null && response.Message.Data is JsonElement je) + node = je.Deserialize(fixture.ClientMesh.JsonSerializerOptions); + if (node?.Content is T typed) return typed; + if (node?.Content is JsonElement contentJe) + return contentJe.Deserialize(fixture.ClientMesh.JsonSerializerOptions); + return null; + } + + /// + /// Exact portal flow: create thread → create cells (verified) → submit → execution → response. + /// + [Fact] + public async Task PortalFlow_CreateThread_CreateCells_Submit_ExecutionCompletes() + { + SharedOrleansFixture.SwappableFactory.SetInner(new PortalFlowEchoChatClientFactory()); + try + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = await GetClientAsync(); + + // Step 1: Create thread + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Portal flow Orleans test", "Roland"); + var createResp = await client.AwaitResponse( + new CreateNodeRequest(threadNode), + o => o.WithTarget(new Address("User/Roland")), ct); + createResp.Message.Success.Should().BeTrue(createResp.Message.Error); + var threadPath = createResp.Message.Node!.Path!; + Output.WriteLine($"Thread: {threadPath}"); + + // Step 2: Create user cell → verify + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + var userCellResp = await client.AwaitResponse( + new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage + { + Role = "user", Text = "Portal flow Orleans test", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.ExecutedInput, CreatedBy = "Roland" + } + }), o => o.WithTarget(new Address(threadPath)), ct); + userCellResp.Message.Success.Should().BeTrue("user cell creation must succeed"); + Output.WriteLine($"User cell created: {userMsgId}"); + + // Step 3: Create response cell → verify + var responseCellResp = await client.AwaitResponse( + new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage + { + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse, AgentName = "Orchestrator" + } + }), o => o.WithTarget(new Address(threadPath)), ct); + responseCellResp.Message.Success.Should().BeTrue("response cell creation must succeed"); + Output.WriteLine($"Response cell created: {responseMsgId}"); + + // Step 4: Submit — updates state, WatchForExecution triggers execution + var submitResp = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Portal flow Orleans test", + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId, + AgentName = "Orchestrator", + ContextPath = "User/Roland" + }, o => o.WithTarget(new Address(threadPath)), ct); + submitResp.Message.Success.Should().BeTrue("submit must succeed"); + Output.WriteLine("Submitted — WatchForExecution should trigger"); + + // Step 5: Poll for execution to complete + var responsePath = $"{threadPath}/{responseMsgId}"; + for (var i = 0; i < 60; i++) + { + var thread = await GetHubContentAsync(client, threadPath, ct); + if (thread is { IsExecuting: false }) + { + Output.WriteLine($"Execution complete after {i * 500}ms"); + + var responseMsg = await GetHubContentAsync(client, responsePath, ct); + responseMsg.Should().NotBeNull("response cell must exist"); + responseMsg!.Text.Should().NotBeNullOrEmpty("agent must have written response"); + Output.WriteLine($"Response: {responseMsg.Text[..Math.Min(100, responseMsg.Text.Length)]}"); + + // Verify user cell + var userMsg = await GetHubContentAsync(client, $"{threadPath}/{userMsgId}", ct); + userMsg.Should().NotBeNull(); + userMsg!.Text.Should().Be("Portal flow Orleans test"); + + Output.WriteLine("PASSED"); + return; + } + await Task.Delay(500, ct); + } + throw new TimeoutException("Execution did not complete"); + } + finally + { + SharedOrleansFixture.SwappableFactory.Reset(); + } + } + + /// + /// Existing thread: second message on a thread that already has messages. + /// Verifies WatchForExecution triggers for new ActiveMessageId. + /// + [Fact] + public async Task ExistingThread_SecondMessage_ExecutionCompletes() + { + SharedOrleansFixture.SwappableFactory.SetInner(new PortalFlowEchoChatClientFactory()); + try + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = await GetClientAsync(); + + // Create thread + first message pair + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Multi-message test", "Roland"); + var createResp = await client.AwaitResponse( + new CreateNodeRequest(threadNode), + o => o.WithTarget(new Address("User/Roland")), ct); + var threadPath = createResp.Message.Node!.Path!; + + var u1 = Guid.NewGuid().ToString("N")[..8]; + var r1 = Guid.NewGuid().ToString("N")[..8]; + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(u1, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "user", Text = "First question", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(r1, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + await client.AwaitResponse(new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = "First question", + UserMessageId = u1, ResponseMessageId = r1, ContextPath = "User/Roland" + }, o => o.WithTarget(new Address(threadPath)), ct); + + // Wait for first execution to complete + for (var i = 0; i < 60; i++) + { + var t = await GetHubContentAsync(client, threadPath, ct); + if (t is { IsExecuting: false }) break; + await Task.Delay(500, ct); + } + Output.WriteLine("First message complete"); + + // Second message — same thread, new cells + var u2 = Guid.NewGuid().ToString("N")[..8]; + var r2 = Guid.NewGuid().ToString("N")[..8]; + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(u2, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "user", Text = "Second question", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(r2, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + await client.AwaitResponse(new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = "Second question", + UserMessageId = u2, ResponseMessageId = r2, ContextPath = "User/Roland" + }, o => o.WithTarget(new Address(threadPath)), ct); + + // Wait for second execution + for (var i = 0; i < 60; i++) + { + var t = await GetHubContentAsync(client, threadPath, ct); + if (t is { IsExecuting: false } && t.Messages.Count >= 4) + { + Output.WriteLine($"Second message complete after {i * 500}ms, Messages={t.Messages.Count}"); + var responseMsg = await GetHubContentAsync(client, $"{threadPath}/{r2}", ct); + responseMsg.Should().NotBeNull(); + responseMsg!.Text.Should().NotBeNullOrEmpty(); + Output.WriteLine($"Response: {responseMsg.Text[..Math.Min(80, responseMsg.Text.Length)]}"); + Output.WriteLine("PASSED"); + return; + } + await Task.Delay(500, ct); + } + throw new TimeoutException("Second execution did not complete"); + } + finally + { + SharedOrleansFixture.SwappableFactory.Reset(); + } + } + + #region Echo LLM + + private class PortalFlowEchoChatClient : IChatClient + { + public ChatClientMetadata Metadata => new("PortalFlowEcho"); + public Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken ct = default) + => Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, $"Echo: {messages.Count()} messages"))); + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken ct = default) + { + yield return new ChatResponseUpdate(ChatRole.Assistant, $"Portal echo: received {messages.Count()} messages."); + await Task.Delay(10, ct); + } + + public object? GetService(Type serviceType, object? key = null) => serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } + } + + private class PortalFlowEchoChatClientFactory : IChatClientFactory + { + public string Name => "PortalFlowEchoFactory"; + public IReadOnlyList Models => ["echo-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => new(chatClient: new PortalFlowEchoChatClient(), instructions: "Echo agent.", + name: config.Id, description: config.Description ?? "", + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); + } + + #endregion +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansReentrancyTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansReentrancyTest.cs new file mode 100644 index 000000000..b3d1a52b1 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansReentrancyTest.cs @@ -0,0 +1,296 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Hosting.Security; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Tests that prove/disprove grain reentrancy during AI execution. +/// Hypothesis: the grain scheduler deadlocks when a tool call (inside InvokeAsync) +/// needs to process a response that arrives as a grain call. +/// +/// Test pattern: +/// 1. Submit a message that triggers a tool call (Get or Patch) +/// 2. The tool call makes a round-trip through the hub +/// 3. If reentrant: the response interleaves, tool completes, execution finishes +/// 4. If deadlocked: timeout +/// +public class OrleansReentrancyTest(ITestOutputHelper output) : TestBase(output) +{ + private TestCluster Cluster { get; set; } = null!; + private IMessageHub ClientMesh => Cluster.Client.ServiceProvider.GetRequiredService(); + + public override async ValueTask InitializeAsync() + { + await base.InitializeAsync(); + var builder = new TestClusterBuilder(); + builder.AddSiloBuilderConfigurator(); + builder.AddClientBuilderConfigurator(); + Cluster = builder.Build(); + await Cluster.DeployAsync(); + } + + public override async ValueTask DisposeAsync() + { + if (Cluster is not null) + await Cluster.DisposeAsync(); + await base.DisposeAsync(); + } + + private async Task GetClientAsync(string id) + { + var client = ClientMesh.ServiceProvider.CreateMessageHub( + new Address("client", id), + config => + { + config.TypeRegistry.AddAITypes(); + return config.AddLayoutClient(); + }); + var accessService = client.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext + { + ObjectId = "Roland", Name = "Roland", Email = "rbuergi@test.com" + }); + await Cluster.Client.ServiceProvider.GetRequiredService() + .RegisterStreamAsync(client.Address, client.DeliverMessage); + return client; + } + + private async Task GetHubContentAsync(IMessageHub client, string path, CancellationToken ct) where T : class + { + var nodeId = path.Contains('/') ? path[(path.LastIndexOf('/') + 1)..] : path; + var response = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address(path)), ct); + var node = response.Message.Data as MeshNode; + if (node == null && response.Message.Data is JsonElement je) + node = je.Deserialize(ClientMesh.JsonSerializerOptions); + if (node?.Content is T typed) return typed; + if (node?.Content is JsonElement contentJe) + return contentJe.Deserialize(ClientMesh.JsonSerializerOptions); + return null; + } + + /// + /// The fake agent calls a tool that requires a round-trip through the hub. + /// If reentrancy works: tool completes, response has tool call result + text. + /// If deadlocked: test times out at 15s. + /// + [Fact(Timeout = 15000)] + public async Task ToolCall_DuringStreaming_DoesNotDeadlock() + { + var ct = new CancellationTokenSource(12.Seconds()).Token; + var suffix = Guid.NewGuid().ToString("N")[..6]; + var client = await GetClientAsync($"reent-{suffix}"); + + // Create thread + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Reentrancy test", "Roland"); + var createResp = await client.AwaitResponse( + new CreateNodeRequest(threadNode), o => o.WithTarget(new Address("User/Roland")), ct); + createResp.Message.Success.Should().BeTrue(createResp.Message.Error); + var threadPath = createResp.Message.Node!.Path!; + Output.WriteLine($"Thread: {threadPath}"); + + // Subscribe to messages + var workspace = client.GetWorkspace(); + var twoMessages = workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => + { + var node = nodes?.Cast().FirstOrDefault(n => n.Path == threadPath); + return (node?.Content as MeshThread)?.Messages ?? []; + }) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + // Submit message — the ToolCallingReentrancyClient will call a tool + Output.WriteLine("Submitting message..."); + var submitResp = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Call a tool please", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResp.Message.Success.Should().BeTrue(submitResp.Message.Error); + Output.WriteLine("Submitted"); + + // Wait for message cells + var msgIds = await twoMessages; + Output.WriteLine($"Messages: [{string.Join(", ", msgIds)}]"); + + // Poll for response text + tool calls + var responsePath = $"{threadPath}/{msgIds[1]}"; + ThreadMessage? response = null; + for (var i = 0; i < 30; i++) + { + response = await GetHubContentAsync(client, responsePath, ct); + if (!string.IsNullOrEmpty(response?.Text) && response?.ToolCalls.Count > 0) + { + Output.WriteLine($"Poll {i}: text={response.Text.Length}ch, toolCalls={response.ToolCalls.Count}"); + break; + } + await Task.Delay(300, ct); + } + + // Verify: execution completed with tool call results + response.Should().NotBeNull("response should exist"); + response!.Text.Should().NotBeNullOrEmpty("agent should produce text after tool call"); + response.ToolCalls.Should().NotBeEmpty("tool calls should be tracked"); + response.ToolCalls.First().Result.Should().NotBeNull("tool call should have completed with a result"); + + Output.WriteLine($"PASSED — text='{response.Text[..Math.Min(50, response.Text.Length)]}', toolCalls={response.ToolCalls.Count}"); + } +} + +/// +/// Fake chat client that always calls a tool before producing text. +/// The tool call (Get) requires a round-trip through the hub. +/// If the grain is deadlocked, the tool call never completes. +/// +internal class ToolCallingReentrancyClient : IChatClient +{ + public ChatClientMetadata Metadata => new("ReentrancyTest"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken cancellationToken = default) + { + var hasFunctionResult = messages.Any(m => m.Contents.OfType().Any()); + if (hasFunctionResult) + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, "Tool call completed successfully. Reentrancy works."))); + + // Call Get tool — requires round-trip through the hub + if (options?.Tools?.Any(t => t.Name == "Get") == true) + { + var call = new FunctionCallContent("test-get", "Get", + new Dictionary { ["path"] = "@User/Roland" }); + return Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, [call]))); + } + + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, "No Get tool available."))); + } + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + var response = await GetResponseAsync(messages, options, cancellationToken); + var msg = response.Messages.First(); + var functionCalls = msg.Contents.OfType().ToList(); + if (functionCalls.Count > 0) + { + yield return new ChatResponseUpdate + { + Role = ChatRole.Assistant, + Contents = [..functionCalls] + }; + yield break; + } + foreach (var word in (msg.Text ?? "Done.").Split(' ')) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return new ChatResponseUpdate(ChatRole.Assistant, word + " "); + await Task.Delay(10, cancellationToken); + } + } + + public object? GetService(Type serviceType, object? serviceKey = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } +} + +internal class ReentrancyTestChatClientFactory : IChatClientFactory +{ + public string Name => "ReentrancyTestFactory"; + public IReadOnlyList Models => ["test-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => new(chatClient: new ToolCallingReentrancyClient(), + instructions: "Test assistant.", + name: config.Id, description: config.Description ?? config.Id, + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); +} + +public class ReentrancyTestSiloConfigurator : ISiloConfigurator, IHostConfigurator +{ + public void Configure(ISiloBuilder siloBuilder) + { + siloBuilder.ConfigureMeshWeaverServer() + .AddMemoryGrainStorageAsDefault(); + } + + public void Configure(IHostBuilder hostBuilder) + { + hostBuilder.UseOrleansMeshServer() + .ConfigurePortalMesh() + .AddGraph() + .AddAI() + .AddRowLevelSecurity() + .AddMeshNodes(new MeshNode("Roland", "User") { Name = "Roland", NodeType = "User" }) + .AddMeshNodes(PublicEditorAccess()) + .ConfigureServices(services => + services.AddSingleton(new ReentrancyTestChatClientFactory())) + .ConfigureDefaultNodeHub(config => config.AddDefaultLayoutAreas()); + } + + private static MeshNode[] PublicEditorAccess() + { + var assignment = new AccessAssignment + { + AccessObject = "Public", + DisplayName = "Public", + Roles = [new RoleAssignment { Role = "Editor" }] + }; + return [new("Public_Access", "User") + { + NodeType = "AccessAssignment", + Name = "Public Access", + Content = assignment, + MainNode = "User", + }]; + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansSubThreadRoutingTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansSubThreadRoutingTest.cs new file mode 100644 index 000000000..2d92c5717 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansSubThreadRoutingTest.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Data; +using MeshWeaver.Fixture; +using MeshWeaver.Graph; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Tests that deeply nested sub-thread paths (delegation pattern) route correctly +/// across multiple path segments in Orleans. Reproduces the production scenario: +/// Parent/_Thread/thread-id/msg-id/sub-thread-id +/// This is 5+ segments deep and requires the RoutingGrain to correctly resolve +/// the path and update the delivery target. +/// +public class OrleansSubThreadRoutingTest(ITestOutputHelper output) : TestBase(output) +{ + private TestCluster Cluster { get; set; } = null!; + private IMessageHub ClientMesh => Cluster.Client.ServiceProvider.GetRequiredService(); + + public override async ValueTask InitializeAsync() + { + await base.InitializeAsync(); + var builder = new TestClusterBuilder(); + builder.AddSiloBuilderConfigurator(); + builder.AddClientBuilderConfigurator(); + Cluster = builder.Build(); + await Cluster.DeployAsync(); + } + + public override async ValueTask DisposeAsync() + { + if (Cluster is not null) + await Cluster.DisposeAsync(); + await base.DisposeAsync(); + } + + private async Task GetClientAsync() + { + var client = ClientMesh.ServiceProvider.CreateMessageHub( + new Address("client", "subrouting"), + config => + { + config.TypeRegistry.AddAITypes(); + return config.AddLayoutClient(); + }); + // Set user identity on the client (simulates Blazor CircuitContext) + var accessService = client.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext + { + ObjectId = "Roland", + Name = "Roland Buergi", + Email = "rbuergi@systemorph.com" + }); + await Cluster.Client.ServiceProvider.GetRequiredService() + .RegisterStreamAsync(client.Address, client.DeliverMessage); + return client; + } + + private async Task CreateNodeAsync(IMessageHub client, MeshNode node, string targetAddress, CancellationToken ct) + { + Output.WriteLine($"CreateNodeRequest: id={node.Id}, ns={node.Namespace}, path={node.Path}, target={targetAddress}"); + var response = await client.AwaitResponse( + new CreateNodeRequest(node), + o => o.WithTarget(new Address(targetAddress)), ct); + Output.WriteLine($"CreateNodeResponse: success={response.Message.Success}, error={response.Message.Error ?? "(none)"}, path={response.Message.Node?.Path ?? "(null)"}"); + response.Message.Success.Should().BeTrue(response.Message.Error); + return response.Message.Node!.Path!; + } + + private IObservable> ObserveThreadMessages(IMessageHub client, string threadPath) + { + var workspace = client.GetWorkspace(); + return workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => + { + var node = nodes?.FirstOrDefault(n => n.Path == threadPath); + var content = node?.Content as MeshThread; + var ids = content?.Messages ?? []; + Output.WriteLine($"[Stream] Thread {threadPath}: {ids.Count} message IDs"); + return (IReadOnlyList)ids; + }); + } + + private async Task GetHubContentAsync(IMessageHub client, string path, CancellationToken ct) where T : class + { + var nodeId = path.Contains('/') ? path[(path.LastIndexOf('/') + 1)..] : path; + var response = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), nodeId)), + o => o.WithTarget(new Address(path)), ct); + var node = response.Message.Data as MeshNode; + if (node == null && response.Message.Data is JsonElement je) + node = je.Deserialize(ClientMesh.JsonSerializerOptions); + if (node?.Content is T typed) return typed; + if (node?.Content is JsonElement contentJe) + return contentJe.Deserialize(ClientMesh.JsonSerializerOptions); + return null; + } + + /// + /// Simulates the delegation pattern: create a thread, submit a message (creates cells), + /// then create a sub-thread under the response cell (deeply nested path) and submit to it. + /// This tests that routing works across 6+ path segments. + /// + /// Path hierarchy: + /// User/Roland/_Thread/my-thread (thread, 4 segments) + /// User/Roland/_Thread/my-thread/msg1 (message, 5 segments) + /// User/Roland/_Thread/my-thread/msg1/sub (sub-thread, 6 segments) + /// + /// The RoutingGrain must resolve the sub-thread grain key correctly and + /// propagate the access context through the entire chain. + /// + [Fact(Timeout = 60000)] + public async Task SubThreadDelegation_RoutesAcrossMultipleSegments() + { + var ct = new CancellationTokenSource(50.Seconds()).Token; + var client = await GetClientAsync(); + + // 1. Create a thread under User/Roland + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Routing test thread", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + Output.WriteLine($"Thread: {threadPath}"); + threadPath.Should().StartWith("User/Roland/_Thread/"); + + // 2. Submit message to create cells (user msg + response msg) + var twoMessages = ObserveThreadMessages(client, threadPath) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + var submitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Test message for sub-thread routing", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); + Output.WriteLine("First SubmitMessageRequest succeeded"); + + var msgIds = await twoMessages; + msgIds.Should().HaveCount(2); + Output.WriteLine($"Message IDs: [{string.Join(", ", msgIds)}]"); + + // Wait for response to stream and stabilize + await Task.Delay(2000, ct); + + // 3. Create sub-thread under the response message (deeply nested path) + var responseMsgId = msgIds[1]; + var parentMsgPath = $"{threadPath}/{responseMsgId}"; + var subThreadId = "sub-thread-routing-test"; + var subThreadPath = $"{parentMsgPath}/{subThreadId}"; + + Output.WriteLine($"Creating sub-thread at: {subThreadPath}"); + Output.WriteLine($" Namespace: {parentMsgPath}"); + Output.WriteLine($" Segments: {subThreadPath.Split('/').Length}"); + + var subThreadNode = new MeshNode(subThreadId, parentMsgPath) + { + Name = "Sub-thread routing test", + NodeType = ThreadNodeType.NodeType, + MainNode = "User/Roland", + Content = new MeshThread + { + CreatedBy = "Roland" + } + }; + + var createdSubThreadPath = await CreateNodeAsync(client, subThreadNode, threadPath, ct); + Output.WriteLine($"Sub-thread created: {createdSubThreadPath}"); + createdSubThreadPath.Should().Be(subThreadPath); + + // 4. Submit message to the sub-thread — this is the critical routing test! + // The sub-thread is 6 segments deep. The RoutingGrain must resolve this + // to the correct grain key and propagate access context. + var subTwoMessages = ObserveThreadMessages(client, subThreadPath) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + Output.WriteLine($"Posting SubmitMessageRequest to sub-thread: {subThreadPath}"); + var subSubmitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = subThreadPath, + UserMessageText = "Hello from sub-thread!", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(subThreadPath)), ct); + + subSubmitResponse.Message.Success.Should().BeTrue( + $"Sub-thread SubmitMessage should succeed but got: {subSubmitResponse.Message.Error}"); + Output.WriteLine("Sub-thread SubmitMessageRequest succeeded!"); + + // 5. Wait for sub-thread cells to appear + var subMsgIds = await subTwoMessages; + subMsgIds.Should().HaveCount(2, "sub-thread should have user message + agent response"); + Output.WriteLine($"Sub-thread message IDs: [{string.Join(", ", subMsgIds)}]"); + + // 6. Verify sub-thread user message content + var subUserMsg = await GetHubContentAsync( + client, $"{subThreadPath}/{subMsgIds[0]}", ct); + subUserMsg.Should().NotBeNull("sub-thread user message should exist"); + subUserMsg!.Role.Should().Be("user"); + subUserMsg.Text.Should().Be("Hello from sub-thread!"); + Output.WriteLine($"Sub-thread user cell verified: '{subUserMsg.Text}'"); + + // 7. Verify sub-thread response streams (wait for content) + ThreadMessage? subResponseMsg = null; + for (var i = 0; i < 30; i++) + { + subResponseMsg = await GetHubContentAsync( + client, $"{subThreadPath}/{subMsgIds[1]}", ct); + if (!string.IsNullOrEmpty(subResponseMsg?.Text)) + break; + await Task.Delay(200, ct); + } + subResponseMsg.Should().NotBeNull("sub-thread response should exist"); + subResponseMsg!.Role.Should().Be("assistant"); + subResponseMsg.Text.Should().NotBeNullOrEmpty("sub-thread agent should stream a response"); + Output.WriteLine($"Sub-thread response: '{subResponseMsg.Text}'"); + } + + /// + /// Verifies that access context propagates correctly when creating and accessing + /// nodes at deeply nested paths. Uses the real submission flow (SubmitMessage → cells) + /// to create intermediate nodes, then creates a sub-thread under them. + /// + [Fact(Timeout = 60000)] + public async Task SubThreadCreation_AccessContextPropagates() + { + var ct = new CancellationTokenSource(50.Seconds()).Token; + var client = await GetClientAsync(); + + // 1. Create a thread + var threadNode = ThreadNodeType.BuildThreadNode("User/Roland", "Access context test", "Roland"); + var threadPath = await CreateNodeAsync(client, threadNode, "User/Roland", ct); + Output.WriteLine($"Thread: {threadPath}"); + + // 2. Submit message to create proper cells (ThreadMessages) via the standard flow + var twoMessages = ObserveThreadMessages(client, threadPath) + .Where(ids => ids.Count >= 2) + .FirstAsync() + .ToTask(ct); + + var submitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Access context test msg", + ContextPath = "User/Roland" + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); + + var msgIds = await twoMessages; + var responseMsgId = msgIds[1]; + Output.WriteLine($"Response message: {responseMsgId}"); + + // Wait for response to stabilize + await Task.Delay(2000, ct); + + // 3. Create a sub-thread under the response message (deeply nested) + var parentMsgPath = $"{threadPath}/{responseMsgId}"; + var subThreadId = "access-ctx-test"; + + var subThreadNode = new MeshNode(subThreadId, parentMsgPath) + { + Name = "Access context sub-thread", + NodeType = ThreadNodeType.NodeType, + MainNode = "User/Roland", + Content = new MeshThread { CreatedBy = "Roland" } + }; + var subThreadPath = await CreateNodeAsync(client, subThreadNode, threadPath, ct); + Output.WriteLine($"Sub-thread created: {subThreadPath}"); + subThreadPath.Should().Be($"{parentMsgPath}/{subThreadId}"); + + // 4. Verify we can read the sub-thread hub content (proves grain activation + access) + var content = await GetHubContentAsync(client, subThreadPath, ct); + content.Should().NotBeNull("sub-thread grain should activate and serve content"); + content!.CreatedBy.Should().Be("Roland"); + Output.WriteLine($"Sub-thread content verified: CreatedBy={content.CreatedBy}"); + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansTestMeshExtensions.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansTestMeshExtensions.cs index 9104f406a..bb36c5e39 100644 --- a/test/MeshWeaver.Hosting.Orleans.Test/OrleansTestMeshExtensions.cs +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansTestMeshExtensions.cs @@ -35,11 +35,6 @@ public static MeshBuilder ConfigurePortalMesh(this MeshBuilder builder) }) .AddGraph() .AddAI() - .ConfigureServices(services => - { - services.AddSingleton(new FakeChatClientFactory()); - return services; - }) .AddKernel(); } diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadAccessTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadAccessTest.cs index 82138ff92..dc9639ff2 100644 --- a/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadAccessTest.cs +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadAccessTest.cs @@ -471,7 +471,6 @@ public async Task ThreadMessageNodes_AreChildrenOfThread() var fullPath = $"{threadPath}/{msgId}"; var msg = await GetHubContentAsync(client, fullPath, ct); msg.Should().NotBeNull($"ThreadMessage at {fullPath} should exist"); - msg!.Id.Should().Be(msgId); Output.WriteLine($"Child node verified: {fullPath} => role={msg.Role}, type={msg.Type}"); } } diff --git a/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadStreamingTest.cs b/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadStreamingTest.cs index 5792590f7..b6660ba62 100644 --- a/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadStreamingTest.cs +++ b/test/MeshWeaver.Hosting.Orleans.Test/OrleansThreadStreamingTest.cs @@ -1,6 +1,5 @@ -using System; +using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.IO; using System.Linq; using System.Reactive.Linq; @@ -12,13 +11,12 @@ using FluentAssertions; using FluentAssertions.Extensions; using MeshWeaver.AI; -using MeshWeaver.Connection.Orleans; using MeshWeaver.Data; using MeshWeaver.Fixture; +using MeshWeaver.Layout; using MeshWeaver.Graph; using MeshWeaver.Graph.Configuration; using MeshWeaver.Hosting.Persistence; -using MeshWeaver.Layout; using MeshWeaver.Mesh; using MeshWeaver.Mesh.Services; using MeshWeaver.Messaging; @@ -262,6 +260,7 @@ public async Task DelegationFlow_SubThreadStreamsText_ParentCompletes() finalResponse.Should().NotBeNull("response message should have text after tool execution completes"); finalResponse!.Text.Should().NotBeNullOrEmpty(); + finalResponse.ToolCalls.Should().NotBeEmpty("response should have tool calls tracked via middleware"); Output.WriteLine("8. Test PASSED"); } @@ -271,10 +270,10 @@ public async Task DelegationFlow_SubThreadStreamsText_ParentCompletes() /// (without page reload). Then sub-thread streams text that appears on the /// sub-thread's response message. Tests the FULL real-world path. /// - [Fact(Timeout = 90000)] + [Fact(Timeout = 30000)] public async Task Delegation_ParentShowsToolCall_SubThreadStreamsText_LiveUpdate() { - var ct = new CancellationTokenSource(80.Seconds()).Token; + var ct = new CancellationTokenSource(25.Seconds()).Token; var client = await GetClientAsync(); var workspace = client.GetWorkspace(); @@ -313,15 +312,19 @@ public async Task Delegation_ParentShowsToolCall_SubThreadStreamsText_LiveUpdate var responsePath = $"{threadPath}/{responseMsgId}"; Output.WriteLine($"3. Response message: {responseMsgId}"); - // 4. Subscribe to the response message node — watch for tool calls appearing + // 4. Subscribe to response message stream — wait for tool call with DelegationPath + Output.WriteLine("4. Subscribing to response message stream for delegation tool call..."); var responseStream = workspace.GetRemoteStream(new Address(responsePath))!; - - // 4. Wait for delegation tool call with DelegationPath on the response stream - Output.WriteLine("4. Waiting for delegation tool call with DelegationPath..."); var msgWithDelegation = await responseStream - .Select(nodes => nodes?.FirstOrDefault(n => n.Path == responsePath)?.Content as ThreadMessage) + .Select(nodes => + { + var msg = nodes?.FirstOrDefault(n => n.Path == responsePath)?.Content as ThreadMessage; + if (msg != null) + Output.WriteLine($" [STREAM] text={msg.Text?.Length ?? 0}ch, toolCalls={msg.ToolCalls.Count}, delegations={msg.ToolCalls.Count(c => !string.IsNullOrEmpty(c.DelegationPath))}"); + return msg; + }) .Where(m => m?.ToolCalls.Any(c => !string.IsNullOrEmpty(c.DelegationPath)) == true) - .Timeout(60.Seconds()) + .Timeout(20.Seconds()) .FirstAsync() .ToTask(ct); @@ -331,12 +334,13 @@ public async Task Delegation_ParentShowsToolCall_SubThreadStreamsText_LiveUpdate // 5. Wait for parent execution to complete (text appears) Output.WriteLine("6. Waiting for parent to complete..."); - var completed = await responseStream - .Select(nodes => nodes?.FirstOrDefault(n => n.Path == responsePath)?.Content as ThreadMessage) - .Where(m => !string.IsNullOrEmpty(m?.Text)) - .Timeout(60.Seconds()) - .FirstAsync() - .ToTask(ct); + ThreadMessage? completed = null; + for (var j = 0; j < 30; j++) + { + completed = await GetHubContentAsync(client, responsePath, ct); + if (!string.IsNullOrEmpty(completed?.Text)) break; + await Task.Delay(500, ct); + } completed!.Text.Should().NotBeNullOrEmpty("parent should have text after delegation completes"); Output.WriteLine($"7. PARENT COMPLETE: text='{completed.Text}', toolCalls={completed.ToolCalls.Count}"); @@ -560,11 +564,30 @@ public ChatClientAgent CreateAgent( ? new DelegatingFakeChatClient(config.Id) : new ToolCallingFakeChatClient(); - return new(chatClient: client, + var agent = new ChatClientAgent(chatClient: client, instructions: config.Instructions ?? "Test assistant.", name: config.Id, description: config.Description ?? config.Id, tools: [AIFunctionFactory.Create((string param) => $"Tool executed with {param}", "test_tool", "A test tool")], loggerFactory: null, services: null); + + // Wrap with function calling middleware — same as production ChatClientAgentFactory + return agent.AsBuilder() + .Use((AIAgent _, FunctionInvocationContext ctx, + Func> next, + CancellationToken ct) => + { + chat.ForwardToolCall?.Invoke(new ToolCallEntry + { + Name = ctx.Function.Name, + DisplayName = ctx.Function.Name, + Arguments = ctx.Arguments?.Count > 0 + ? string.Join(", ", ctx.Arguments.Select(kv => $"{kv.Key}={kv.Value}")) + : null, + Timestamp = DateTime.UtcNow + }); + return next(ctx, ct); + }) + .Build() as ChatClientAgent ?? agent; } public Task CreateAgentAsync( diff --git a/test/MeshWeaver.Hosting.Orleans.Test/SharedOrleansFixture.cs b/test/MeshWeaver.Hosting.Orleans.Test/SharedOrleansFixture.cs new file mode 100644 index 000000000..9b8e60f64 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/SharedOrleansFixture.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Agents.AI; +using MeshWeaver.AI; +using MeshWeaver.Connection.Orleans; +using MeshWeaver.Graph; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Hosting.Security; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Layout; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Orleans.Hosting; +using Orleans.TestingHost; +using MeshWeaver.Fixture; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.Orleans.Test; + +/// +/// Shared Orleans TestCluster fixture. Boots ONCE per test assembly. +/// All test classes that use [Collection(nameof(OrleansClusterCollection))] +/// share this single cluster — no grain state leaks between test classes. +/// +/// Configuration: production-like (Graph + AI + RLS + memory persistence). +/// Chat factory: FakeChatClientFactory by default. Tests that need a +/// different factory should use TestChatFactoryScope to swap it temporarily. +/// +public class SharedOrleansFixture : IAsyncLifetime +{ + public TestCluster Cluster { get; private set; } = null!; + public IMessageHub ClientMesh => Cluster.Client.ServiceProvider.GetRequiredService(); + + /// + /// The swappable chat factory. Tests replace this to use different fakes. + /// + internal static SwappableChatClientFactory SwappableFactory { get; } = new(); + + public async ValueTask InitializeAsync() + { + var builder = new TestClusterBuilder(); + builder.AddSiloBuilderConfigurator(); + builder.AddClientBuilderConfigurator(); + Cluster = builder.Build(); + await Cluster.DeployAsync(); + } + + public async ValueTask DisposeAsync() + { + if (Cluster is not null) + await Cluster.DisposeAsync(); + } + + /// + /// Creates a client hub with user identity — same as Blazor portal. + /// Each test should use a unique clientId to avoid address collisions. + /// + public async Task GetClientAsync(string clientId, string userId = "Roland") + { + var client = ClientMesh.ServiceProvider.CreateMessageHub( + new Address("client", clientId), + config => + { + config.TypeRegistry.AddAITypes(); + return config.AddLayoutClient(); + }); + var accessService = client.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext + { + ObjectId = userId, + Name = userId, + Email = $"{userId.ToLowerInvariant()}@test.com" + }); + // Register on BOTH client and silo routing services so responses can route back + await Cluster.Client.ServiceProvider.GetRequiredService() + .RegisterStreamAsync(client.Address, client.DeliverMessage); + // Register on the SILO's routing service so responses route back to client. + // In prod, portal and silo share one IRoutingService. In TestCluster they're separate. + // Without this, response routing tries to activate a grain for the client address → fails. + // Access silo's IRoutingService via reflection (InProcessSiloHandle.SiloHost.Services) + // Try multiple paths to find the silo's IRoutingService + var primarySilo = Cluster.Primary; + var siloHost = primarySilo.GetType().GetProperty("SiloHost")?.GetValue(primarySilo) as IHost; + var siloRouting = siloHost?.Services.GetService() + ?? siloHost?.Services.GetService()?.ServiceProvider.GetService(); + if (siloRouting != null) + await siloRouting.RegisterStreamAsync(client.Address, + (d, _) => Task.FromResult(client.DeliverMessage(d))); + return client; + } +} + +/// +/// xUnit collection that shares a single Orleans TestCluster. +/// All test classes annotated with [Collection(nameof(OrleansClusterCollection))] +/// share the same cluster instance. +/// +[CollectionDefinition(nameof(OrleansClusterCollection))] +public class OrleansClusterCollection : ICollectionFixture; + +/// +/// Swappable IChatClientFactory that delegates to an inner factory. +/// Tests swap the inner factory to control agent behavior. +/// Thread-safe via volatile reference. +/// +internal class SwappableChatClientFactory : IChatClientFactory +{ + private volatile IChatClientFactory _inner = new FakeChatClientFactory(); + + public string Name => _inner.Name; + public IReadOnlyList Models => _inner.Models; + public int Order => _inner.Order; + + public void SetInner(IChatClientFactory factory) => _inner = factory; + public void Reset() => _inner = new FakeChatClientFactory(); + + public ChatClientAgent CreateAgent( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => _inner.CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName); + + public Task CreateAgentAsync( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => _inner.CreateAgentAsync(config, chat, existingAgents, hierarchyAgents, modelName); +} + +/// +/// Production-like silo: Graph + AI + RLS + memory persistence. +/// Pre-seeds Roland user and Public Editor access. +/// Uses SwappableChatClientFactory so tests can control agent behavior. +/// +public class SharedSiloConfigurator : ISiloConfigurator, IHostConfigurator +{ + public void Configure(ISiloBuilder siloBuilder) + { + siloBuilder.ConfigureMeshWeaverServer() + .AddMemoryGrainStorageAsDefault() + .ConfigureLogging(logging => logging.AddXUnitLogger()); + } + + public void Configure(IHostBuilder hostBuilder) + { + hostBuilder.UseOrleansMeshServer() + .ConfigurePortalMesh() + .AddGraph() + .AddAI() + .AddRowLevelSecurity() + .AddMeshNodes( + new MeshNode("Roland", "User") { Name = "Roland", NodeType = "User" }) + .AddMeshNodes(ChatHistoryTestData()) + .AddMeshNodes(PublicEditorAccess()) + .ConfigureServices(services => + services.AddSingleton(SharedOrleansFixture.SwappableFactory)) + .ConfigureDefaultNodeHub(config => config.AddDefaultLayoutAreas()); + } + + /// + /// Pre-seeded thread with 4 messages for OrleansChatHistoryTest cold-start scenario. + /// + private static MeshNode[] ChatHistoryTestData() + { + const string tp = "User/Roland/_Thread/history-cold-start"; + return + [ + new("history-cold-start", "User/Roland/_Thread") + { + Name = "History cold start test", NodeType = ThreadNodeType.NodeType, + MainNode = "User/Roland", + Content = new MeshThread + { + CreatedBy = "Roland", + Messages = System.Collections.Immutable.ImmutableList.Create( + "msg1-user", "msg1-assistant", "msg2-user", "msg2-assistant") + } + }, + new("msg1-user", tp) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "user", Text = "First question", Type = ThreadMessageType.ExecutedInput } + }, + new("msg1-assistant", tp) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "assistant", Text = "First answer.", Type = ThreadMessageType.AgentResponse } + }, + new("msg2-user", tp) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "user", Text = "Second question", Type = ThreadMessageType.ExecutedInput } + }, + new("msg2-assistant", tp) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = "User/Roland", + Content = new ThreadMessage { Role = "assistant", Text = "Second answer.", Type = ThreadMessageType.AgentResponse } + } + ]; + } + + private static MeshNode[] PublicEditorAccess() + { + var assignment = new AccessAssignment + { + AccessObject = "Public", + DisplayName = "Public", + Roles = [new RoleAssignment { Role = "Editor" }] + }; + return + [ + new("Public_Access", "User") + { + NodeType = "AccessAssignment", + Name = "Public Access", + Content = assignment, + MainNode = "User", + } + ]; + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/appsettings.json b/test/MeshWeaver.Hosting.Orleans.Test/appsettings.json new file mode 100644 index 000000000..529f65b6b --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning", + "MeshWeaver.Hosting.Orleans": "Debug", + "MeshWeaver.AI.AgentChatClient": "Debug", + "MeshWeaver.Connection.Orleans": "Debug" + } + } +} diff --git a/test/MeshWeaver.Hosting.Orleans.Test/xunit.runner.json b/test/MeshWeaver.Hosting.Orleans.Test/xunit.runner.json new file mode 100644 index 000000000..c46ded3d8 --- /dev/null +++ b/test/MeshWeaver.Hosting.Orleans.Test/xunit.runner.json @@ -0,0 +1,6 @@ +{ + "parallelizeAssembly": false, + "parallelizeTestCollections": false, + "maxParallelThreads": 1, + "methodTimeout": 30000 +} diff --git a/test/MeshWeaver.Hosting.PostgreSql.Test/CrossPartitionSearchTests.cs b/test/MeshWeaver.Hosting.PostgreSql.Test/CrossPartitionSearchTests.cs index e6bc7bdc0..acdc0adda 100644 --- a/test/MeshWeaver.Hosting.PostgreSql.Test/CrossPartitionSearchTests.cs +++ b/test/MeshWeaver.Hosting.PostgreSql.Test/CrossPartitionSearchTests.cs @@ -19,10 +19,10 @@ namespace MeshWeaver.Hosting.PostgreSql.Test; /// /// Tests cross-partition search with multiple organizations on PostgreSQL. -/// Sets up 3 orgs (ACME, PartnerRe, Contoso) each in their own schema, +/// Sets up 3 orgs (ACME, FutuRe, Contoso) each in their own schema, /// with threads and activity, then verifies global queries find them all. /// -/// This reproduces the production scenario where PartnerRe wasn't +/// This reproduces the production scenario where FutuRe wasn't /// visible in global search. /// [Collection("PostgreSql")] @@ -56,7 +56,7 @@ public CrossPartitionSearchTests(PostgreSqlFixture fixture) var adminAdapter = _fixture.StorageAdapter; // Create 3 org schemas - var orgNames = new[] { "ACME", "PartnerRe", "Contoso" }; + var orgNames = new[] { "ACME", "FutuRe", "Contoso" }; var partitions = new Dictionary(); foreach (var org in orgNames) @@ -245,7 +245,7 @@ public async Task CrossPartition_TextSearchFindsAcrossPartitions() // All 3 orgs should have a matching "Annual Report" allMatches.Should().HaveCount(3, "each org has an 'Annual Report' document"); allMatches.Select(n => n.Name).Should().Contain("ACME Annual Report"); - allMatches.Select(n => n.Name).Should().Contain("PartnerRe Annual Report"); + allMatches.Select(n => n.Name).Should().Contain("FutuRe Annual Report"); allMatches.Select(n => n.Name).Should().Contain("Contoso Annual Report"); } @@ -295,7 +295,7 @@ public async Task StoredProc_SearchAcrossSchemas_ReturnsAllOrgs() results.Should().NotBeEmpty("stored proc should return nodes from all schemas"); results.Select(n => n.Id).Should().Contain("ACME"); - results.Select(n => n.Id).Should().Contain("PartnerRe"); + results.Select(n => n.Id).Should().Contain("FutuRe"); results.Select(n => n.Id).Should().Contain("Contoso"); } @@ -308,13 +308,13 @@ public async Task StoredProc_SearchAcrossSchemas_TextSearch() var schemas = partitions.Keys.Select(k => k.ToLowerInvariant()).ToList(); await PopulateSearchableSchemasAsync(schemas, ct); - // Text search for "Partner" - var textFilter = "COALESCE(n.name,'') || ' ' || COALESCE(n.namespace || '/' || n.id,'') || ' ' || COALESCE(n.node_type,'') ILIKE '%partner%'"; + // Text search for "FutuRe" + var textFilter = "COALESCE(n.name,'') || ' ' || COALESCE(n.namespace || '/' || n.id,'') || ' ' || COALESCE(n.node_type,'') ILIKE '%future%'"; var results = await CallSearchAcrossSchemasAsync(textFilter, null, "last_modified DESC", 50, ct); - results.Should().NotBeEmpty("should find PartnerRe by text search"); - results.Select(n => n.Id).Should().Contain("PartnerRe"); - results.Should().NotContain(n => n.Id == "ACME", "ACME doesn't match 'partner'"); + results.Should().NotBeEmpty("should find FutuRe by text search"); + results.Select(n => n.Id).Should().Contain("FutuRe"); + results.Should().NotContain(n => n.Id == "ACME", "ACME doesn't match 'future'"); } [Fact(Timeout = 60000)] @@ -337,13 +337,13 @@ public async Task StoredProc_SearchAcrossSchemas_ExcludesUnsearchableSchemas() var ct = TestContext.Current.CancellationToken; var (adminAdapter, partitions) = await SetupMultiOrgEnvironmentAsync(ct); - // Only include ACME and PartnerRe (exclude Contoso) - await PopulateSearchableSchemasAsync(["acme", "partnerre"], ct); + // Only include ACME and FutuRe (exclude Contoso) + await PopulateSearchableSchemasAsync(["acme", "future"], ct); var results = await CallSearchAcrossSchemasAsync("", null, "last_modified DESC", 50, ct); results.Select(n => n.Id).Should().Contain("ACME"); - results.Select(n => n.Id).Should().Contain("PartnerRe"); + results.Select(n => n.Id).Should().Contain("FutuRe"); results.Should().NotContain(n => n.Id == "Contoso", "Contoso is not in searchable_schemas"); } @@ -379,10 +379,21 @@ public async Task StoredProc_SearchAcrossSchemas_AccessControlFilters() var results = await CallSearchAcrossSchemasAsync("", "testuser", "last_modified DESC", 50, ct); - // testuser should see public_read nodes from all schemas + ACME-specific nodes + // testuser has partition_access only to ACME — should only see ACME nodes results.Should().NotBeEmpty(); - // ACME nodes should be visible (partition_access + effective permissions) results.Select(n => n.Id).Should().Contain("ACME"); + + // CRITICAL: public_read must NOT bypass partition_access. + // testuser has NO partition_access to FutuRe or Contoso, + // so those nodes must NOT appear even though Markdown is public_read. + results.Should().NotContain(n => n.Id == "FutuRe", + "testuser has no partition_access to FutuRe — public_read must not bypass partition check"); + results.Should().NotContain(n => n.Id == "Contoso", + "testuser has no partition_access to Contoso — public_read must not bypass partition check"); + results.Should().NotContain(n => n.Id == "Report" && n.Namespace == "FutuRe", + "FutuRe child nodes must also be hidden"); + results.Should().NotContain(n => n.Id == "Report" && n.Namespace == "Contoso", + "Contoso child nodes must also be hidden"); } [Fact(Timeout = 60000)] @@ -420,7 +431,7 @@ public async Task CrossSchema_QueryNodesAcrossSchemas_ReturnsResults() results.Should().NotBeEmpty("cross-schema query should return nodes"); results.Select(n => n.Id).Should().Contain("ACME"); - results.Select(n => n.Id).Should().Contain("PartnerRe"); + results.Select(n => n.Id).Should().Contain("FutuRe"); results.Select(n => n.Id).Should().Contain("Contoso"); } diff --git a/test/MeshWeaver.Hosting.PostgreSql.Test/FirstUserOnboardingTests.cs b/test/MeshWeaver.Hosting.PostgreSql.Test/FirstUserOnboardingTests.cs index 12798366d..c22160b35 100644 --- a/test/MeshWeaver.Hosting.PostgreSql.Test/FirstUserOnboardingTests.cs +++ b/test/MeshWeaver.Hosting.PostgreSql.Test/FirstUserOnboardingTests.cs @@ -180,12 +180,19 @@ await ac.SyncNodeTypePermissionsAsync( // Populate searchable_schemas await PopulateSearchableSchemasAsync(orgNames.Select(o => o.ToLowerInvariant()), ct); + // Grant partition_access to globaladmin for all org schemas + await using (var cmd = _fixture.DataSource.CreateCommand( + "DELETE FROM public.partition_access; " + + "INSERT INTO public.partition_access (user_id, partition) VALUES " + + "('globaladmin', 'orgalpha'), ('globaladmin', 'orgbeta')")) + await cmd.ExecuteNonQueryAsync(ct); + // Cross-schema search for Organization nodes as globaladmin var results = await CallSearchAcrossSchemasAsync( $"LOWER(n.node_type) = '{OrganizationNodeType.NodeType.ToLowerInvariant()}'", username, "last_modified DESC", 50, ct); - results.Should().HaveCount(2, "Global admin should see all organizations"); + results.Should().HaveCount(2, "Global admin should see all organizations (has partition_access to both)"); results.Select(n => n.Name).Should().Contain("OrgAlpha Corp"); results.Select(n => n.Name).Should().Contain("OrgBeta Corp"); } diff --git a/test/MeshWeaver.Hosting.PostgreSql.Test/GlobalAdminOrganizationSearchTests.cs b/test/MeshWeaver.Hosting.PostgreSql.Test/GlobalAdminOrganizationSearchTests.cs index 7b8a52234..35e9b45e5 100644 --- a/test/MeshWeaver.Hosting.PostgreSql.Test/GlobalAdminOrganizationSearchTests.cs +++ b/test/MeshWeaver.Hosting.PostgreSql.Test/GlobalAdminOrganizationSearchTests.cs @@ -89,11 +89,12 @@ public async Task GlobalAdmin_SeesAllOrganizations_ViaCrossSchemaSearch() var ct = TestContext.Current.CancellationToken; var partitions = await SetupOrganizationsAsync(ct); - // Global Admin: has partition_access to admin + effective permissions at root + // Global Admin: has partition_access to ALL org partitions const string adminUserId = "globaladmin"; await using (var cmd = _fixture.DataSource.CreateCommand( "DELETE FROM public.partition_access; " + - "INSERT INTO public.partition_access (user_id, partition) VALUES ('globaladmin', 'public')")) + "INSERT INTO public.partition_access (user_id, partition) VALUES " + + "('globaladmin', 'alphaorg'), ('globaladmin', 'betaorg'), ('globaladmin', 'gammaorg')")) await cmd.ExecuteNonQueryAsync(ct); // Query: nodeType:Organization — the fixed query for Organization Search @@ -109,12 +110,12 @@ public async Task GlobalAdmin_SeesAllOrganizations_ViaCrossSchemaSearch() } [Fact(Timeout = 60000)] - public async Task OrganizationPublicRead_VisibleToAnyUser() + public async Task PublicRead_StillRequiresPartitionAccess() { var ct = TestContext.Current.CancellationToken; await SetupOrganizationsAsync(ct); - // Regular user with no partition_access — should still see Organizations via public_read + // Regular user with NO partition_access — even public_read must not bypass partition check await using (var cmd = _fixture.DataSource.CreateCommand("DELETE FROM public.partition_access")) await cmd.ExecuteNonQueryAsync(ct); @@ -122,29 +123,34 @@ public async Task OrganizationPublicRead_VisibleToAnyUser() var results = await CallSearchAcrossSchemasAsync( nodeTypeFilter, "regularuser", "last_modified DESC", 50, ct); - results.Should().HaveCount(3, - "Organization has PublicRead=true — any authenticated user should see all orgs"); - results.Select(n => n.Id).Should().Contain("AlphaOrg"); - results.Select(n => n.Id).Should().Contain("BetaOrg"); - results.Select(n => n.Id).Should().Contain("GammaOrg"); + results.Should().BeEmpty( + "public_read must NOT bypass partition_access — user without partition access sees nothing"); } [Fact(Timeout = 60000)] - public async Task NonOrgNodes_NotVisibleWithoutAccess() + public async Task PublicRead_SkipsNodeLevelChecks_WithinAccessiblePartition() { var ct = TestContext.Current.CancellationToken; await SetupOrganizationsAsync(ct); - // Regular user with no partition_access — Markdown nodes are NOT public_read - await using (var cmd = _fixture.DataSource.CreateCommand("DELETE FROM public.partition_access")) + // Give user partition_access to AlphaOrg only (no node-level permissions) + await using (var cmd = _fixture.DataSource.CreateCommand( + "DELETE FROM public.partition_access; " + + "INSERT INTO public.partition_access (user_id, partition) VALUES ('regularuser', 'alphaorg')")) await cmd.ExecuteNonQueryAsync(ct); - // Search for all nodes (no nodeType filter) — should only get Organization (public_read) + // Search for all nodes — public_read types visible without node-level perms, but only in alphaorg var results = await CallSearchAcrossSchemasAsync( "", "regularuser", "last_modified DESC", 50, ct); - results.Should().OnlyContain(n => n.NodeType == OrganizationNodeType.NodeType, - "Only Organization nodes should be visible without partition access (they're PublicRead)"); + // Should see Organization nodes from AlphaOrg (public_read + partition_access) + results.Should().Contain(n => n.Id == "AlphaOrg", + "AlphaOrg Organization should be visible (public_read + partition_access)"); + // Should NOT see BetaOrg or GammaOrg (no partition_access) + results.Should().NotContain(n => n.Id == "BetaOrg", + "BetaOrg should be hidden — no partition_access"); + results.Should().NotContain(n => n.Id == "GammaOrg", + "GammaOrg should be hidden — no partition_access"); } // ── Helpers ────────────────────────────────────────────────────── diff --git a/test/MeshWeaver.Hosting.PostgreSql.Test/ThreadMessageChatTests.cs b/test/MeshWeaver.Hosting.PostgreSql.Test/ThreadMessageChatTests.cs index aa215c160..99c1a2c98 100644 --- a/test/MeshWeaver.Hosting.PostgreSql.Test/ThreadMessageChatTests.cs +++ b/test/MeshWeaver.Hosting.PostgreSql.Test/ThreadMessageChatTests.cs @@ -131,7 +131,6 @@ await _threadAdapter.WriteAsync(new MeshNode("chat-msg", "User/alice/_Thread") MainNode = "User/alice", Content = new ThreadMessage { - Id = "msg-1", Role = "user", AuthorName = "Alice", Text = "Hello, how are you?", @@ -149,7 +148,6 @@ await _threadAdapter.WriteAsync(new MeshNode("chat-msg", "User/alice/_Thread") MainNode = "User/alice", Content = new ThreadMessage { - Id = "msg-2", Role = "assistant", Text = "I'm doing well, thanks for asking!", Timestamp = now.AddSeconds(1), @@ -203,7 +201,6 @@ public async Task ReadMessage_RoundTripsContent() MainNode = "User/carol", Content = new ThreadMessage { - Id = "msg-rt", Role = "user", AuthorName = "Carol", Text = "This is a test message", @@ -238,7 +235,6 @@ await _messageAdapter.WriteAsync(new MeshNode($"m-{i}", threadNs) MainNode = "User/dave", Content = new ThreadMessage { - Id = $"m-{i}", Role = role, Text = $"Message {i} text", Timestamp = now.AddSeconds(i), @@ -268,7 +264,6 @@ await _messageAdapter.WriteAsync(new MeshNode("del-msg", threadNs) MainNode = "User/eve", Content = new ThreadMessage { - Id = "del-msg", Role = "user", Text = "Delete me", } @@ -295,7 +290,7 @@ await _messageAdapter.WriteAsync(new MeshNode("msg-t1", ns1) Name = "Thread 1 msg", NodeType = "ThreadMessage", MainNode = "User/frank", - Content = new ThreadMessage { Id = "msg-t1", Role = "user", Text = "In thread 1" } + Content = new ThreadMessage { Role = "user", Text = "In thread 1" } }, _options, ct); // Thread 2 messages @@ -305,14 +300,14 @@ await _messageAdapter.WriteAsync(new MeshNode("msg-t2a", ns2) Name = "Thread 2 msg A", NodeType = "ThreadMessage", MainNode = "User/frank", - Content = new ThreadMessage { Id = "msg-t2a", Role = "user", Text = "In thread 2 A" } + Content = new ThreadMessage { Role = "user", Text = "In thread 2 A" } }, _options, ct); await _messageAdapter.WriteAsync(new MeshNode("msg-t2b", ns2) { Name = "Thread 2 msg B", NodeType = "ThreadMessage", MainNode = "User/frank", - Content = new ThreadMessage { Id = "msg-t2b", Role = "assistant", Text = "In thread 2 B" } + Content = new ThreadMessage { Role = "assistant", Text = "In thread 2 B" } }, _options, ct); // List thread 1 messages @@ -338,7 +333,6 @@ await _messageAdapter.WriteAsync(new MeshNode("upd-msg", ns) MainNode = "User/grace", Content = new ThreadMessage { - Id = "upd-msg", Role = "user", Text = "Original text" } @@ -352,7 +346,6 @@ await _messageAdapter.WriteAsync(new MeshNode("upd-msg", ns) MainNode = "User/grace", Content = new ThreadMessage { - Id = "upd-msg", Role = "user", Text = "Updated text" } @@ -491,7 +484,7 @@ await _messageAdapter.WriteAsync(new MeshNode("1", "User/alice/_Thread/conv-q") Order = 1, Content = new ThreadMessage { - Id = "1", Role = "user", Text = "Hello", + Role = "user", Text = "Hello", Timestamp = now, Type = ThreadMessageType.ExecutedInput } }, _options, ct); @@ -504,7 +497,7 @@ await _messageAdapter.WriteAsync(new MeshNode("2", "User/alice/_Thread/conv-q") Order = 2, Content = new ThreadMessage { - Id = "2", Role = "assistant", Text = "Hi there!", + Role = "assistant", Text = "Hi there!", Timestamp = now.AddSeconds(1), Type = ThreadMessageType.AgentResponse } }, _options, ct); @@ -720,7 +713,6 @@ await _messageAdapter.WriteAsync(new MeshNode("r1", "User/alice/_Thread/resolve- Order = 1, Content = new ThreadMessage { - Id = "r1", Role = "user", Text = "Hello", Timestamp = DateTime.UtcNow, @@ -784,7 +776,7 @@ await _messageAdapter.WriteAsync(new MeshNode(userMsgId, threadPath) Order = 1, Content = new ThreadMessage { - Id = userMsgId, Role = "user", Text = "Hello from e2e", + Role = "user", Text = "Hello from e2e", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } }, _options, ct); @@ -798,7 +790,7 @@ await _messageAdapter.WriteAsync(new MeshNode(responseMsgId, threadPath) Order = 2, Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "", + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } }, _options, ct); @@ -824,7 +816,7 @@ await _messageAdapter.WriteAsync(new MeshNode(responseMsgId, threadPath) Order = 2, Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", + Role = "assistant", Text = "This is the streamed response.", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } @@ -947,7 +939,7 @@ await _messageAdapter.WriteAsync(new MeshNode("m1", threadPath) Order = 1, Content = new ThreadMessage { - Id = "m1", Role = "user", Text = "Hello", + Role = "user", Text = "Hello", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } }, _options, ct); @@ -960,7 +952,7 @@ await _messageAdapter.WriteAsync(new MeshNode("m2", threadPath) Order = 2, Content = new ThreadMessage { - Id = "m2", Role = "assistant", Text = "Hi there!", + Role = "assistant", Text = "Hi there!", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } }, _options, ct); diff --git a/test/MeshWeaver.Hosting.PostgreSql.Test/ThreadPathResolutionTest.cs b/test/MeshWeaver.Hosting.PostgreSql.Test/ThreadPathResolutionTest.cs new file mode 100644 index 000000000..f085c42f6 --- /dev/null +++ b/test/MeshWeaver.Hosting.PostgreSql.Test/ThreadPathResolutionTest.cs @@ -0,0 +1,237 @@ +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Hosting.PostgreSql.Test; + +/// +/// Tests that deeply nested _Thread paths resolve correctly in PostgreSQL. +/// Thread and sub-thread nodes must be stored in the "threads" satellite table +/// and the path resolution must find them there for the entire sub-path. +/// +/// Reproduces the production bug: delegation creates a sub-thread at +/// Org/_Thread/thread-id/msg-id/sub-thread-id +/// but path resolution can't find it because it looks in mesh_nodes +/// instead of threads. +/// +[Collection("PostgreSql")] +public class ThreadPathResolutionTest +{ + private readonly PostgreSqlFixture _fixture; + private readonly JsonSerializerOptions _options = new(); + + public ThreadPathResolutionTest(PostgreSqlFixture fixture) + { + _fixture = fixture; + } + + [Fact(Timeout = 60000)] + public async Task ThreadNode_StoredInThreadsTable_FoundByGetNodeAsync() + { + var ct = TestContext.Current.CancellationToken; + await _fixture.CleanDataAsync(); + + var partitionDef = new PartitionDefinition + { + Namespace = "TestOrg", + Schema = "testorg", + TableMappings = PartitionDefinition.StandardTableMappings + }; + + var (ds, adapter) = await _fixture.CreateSchemaAdapterAsync("testorg", partitionDef, ct); + + // Create org root in mesh_nodes + await adapter.WriteAsync(new MeshNode("TestOrg") { Name = "Test Org", NodeType = "Markdown" }, _options, ct); + + // Create a thread in threads table (path contains _Thread) + var threadNode = new MeshNode("my-thread", "TestOrg/_Thread") + { + Name = "Test Thread", + NodeType = "Thread", + MainNode = "TestOrg", + Content = new MeshThread { CreatedBy = "testuser" } + }; + await adapter.WriteAsync(threadNode, _options, ct); + + // Verify thread is readable by path + var found = await adapter.ReadAsync("TestOrg/_Thread/my-thread", _options, ct); + found.Should().NotBeNull("thread should be found in threads table"); + found!.Name.Should().Be("Test Thread"); + } + + [Fact(Timeout = 60000)] + public async Task ThreadMessage_UnderThread_FoundByGetNodeAsync() + { + var ct = TestContext.Current.CancellationToken; + await _fixture.CleanDataAsync(); + + var partitionDef = new PartitionDefinition + { + Namespace = "TestOrg", + Schema = "testorg", + TableMappings = PartitionDefinition.StandardTableMappings + }; + + var (ds, adapter) = await _fixture.CreateSchemaAdapterAsync("testorg", partitionDef, ct); + + await adapter.WriteAsync(new MeshNode("TestOrg") { Name = "Test Org", NodeType = "Markdown" }, _options, ct); + + // Thread + await adapter.WriteAsync(new MeshNode("my-thread", "TestOrg/_Thread") + { + Name = "Test Thread", NodeType = "Thread", MainNode = "TestOrg", + Content = new MeshThread() + }, _options, ct); + + // ThreadMessage under thread + await adapter.WriteAsync(new MeshNode("msg1", "TestOrg/_Thread/my-thread") + { + Name = "Message 1", NodeType = "ThreadMessage", MainNode = "TestOrg", + Content = new MeshWeaver.AI.ThreadMessage { Role = "user", Text = "Hello" } + }, _options, ct); + + // Verify message is found + var found = await adapter.ReadAsync("TestOrg/_Thread/my-thread/msg1", _options, ct); + found.Should().NotBeNull("ThreadMessage should be found in threads table"); + found!.NodeType.Should().Be("ThreadMessage"); + } + + [Fact(Timeout = 60000)] + public async Task SubThread_DeeplyNested_FoundByGetNodeAsync() + { + var ct = TestContext.Current.CancellationToken; + await _fixture.CleanDataAsync(); + + var partitionDef = new PartitionDefinition + { + Namespace = "TestOrg", + Schema = "testorg", + TableMappings = PartitionDefinition.StandardTableMappings + }; + + var (ds, adapter) = await _fixture.CreateSchemaAdapterAsync("testorg", partitionDef, ct); + + await adapter.WriteAsync(new MeshNode("TestOrg") { Name = "Test Org", NodeType = "Markdown" }, _options, ct); + + // Thread → Message → Sub-thread (delegation pattern) + await adapter.WriteAsync(new MeshNode("parent-thread", "TestOrg/_Thread") + { + Name = "Parent Thread", NodeType = "Thread", MainNode = "TestOrg", + Content = new MeshThread() + }, _options, ct); + + await adapter.WriteAsync(new MeshNode("msg1", "TestOrg/_Thread/parent-thread") + { + Name = "Response", NodeType = "ThreadMessage", MainNode = "TestOrg", + Content = new MeshWeaver.AI.ThreadMessage { Role = "assistant", Text = "..." } + }, _options, ct); + + // Sub-thread: 6 segments deep + var subThreadPath = "TestOrg/_Thread/parent-thread/msg1/sub-thread"; + await adapter.WriteAsync(new MeshNode("sub-thread", "TestOrg/_Thread/parent-thread/msg1") + { + Name = "Sub Thread", NodeType = "Thread", MainNode = "TestOrg", + Content = new MeshThread() + }, _options, ct); + + // Verify sub-thread is found (must resolve to threads table via _Thread in path) + var found = await adapter.ReadAsync(subThreadPath, _options, ct); + found.Should().NotBeNull("sub-thread should be found in threads table via _Thread path segment"); + found!.Name.Should().Be("Sub Thread"); + found.NodeType.Should().Be("Thread"); + } + + [Fact(Timeout = 60000)] + public async Task SubThread_FoundByFindBestPrefixMatchAsync() + { + var ct = TestContext.Current.CancellationToken; + await _fixture.CleanDataAsync(); + + var partitionDef = new PartitionDefinition + { + Namespace = "TestOrg", + Schema = "testorg", + TableMappings = PartitionDefinition.StandardTableMappings + }; + + var (ds, adapter) = await _fixture.CreateSchemaAdapterAsync("testorg", partitionDef, ct); + + await adapter.WriteAsync(new MeshNode("TestOrg") { Name = "Test Org", NodeType = "Markdown" }, _options, ct); + + await adapter.WriteAsync(new MeshNode("parent-thread", "TestOrg/_Thread") + { + Name = "Parent Thread", NodeType = "Thread", MainNode = "TestOrg", + Content = new MeshThread() + }, _options, ct); + + await adapter.WriteAsync(new MeshNode("msg1", "TestOrg/_Thread/parent-thread") + { + Name = "Response", NodeType = "ThreadMessage", MainNode = "TestOrg", + Content = new MeshWeaver.AI.ThreadMessage { Role = "assistant", Text = "..." } + }, _options, ct); + + await adapter.WriteAsync(new MeshNode("sub-thread", "TestOrg/_Thread/parent-thread/msg1") + { + Name = "Sub Thread", NodeType = "Thread", MainNode = "TestOrg", + Content = new MeshThread() + }, _options, ct); + + // FindBestPrefixMatch for the sub-thread path — must find it in threads table + var (match, segments) = await adapter.FindBestPrefixMatchAsync( + "TestOrg/_Thread/parent-thread/msg1/sub-thread", _options, ct); + + match.Should().NotBeNull("FindBestPrefixMatch should find sub-thread in threads table"); + match!.Path.Should().Be("TestOrg/_Thread/parent-thread/msg1/sub-thread"); + segments.Should().Be(5, "all 5 segments should match"); + } + + [Fact(Timeout = 60000)] + public async Task SubThread_FoundByFindBestPrefixMatch_ForDeeperPath() + { + var ct = TestContext.Current.CancellationToken; + await _fixture.CleanDataAsync(); + + var partitionDef = new PartitionDefinition + { + Namespace = "TestOrg", + Schema = "testorg", + TableMappings = PartitionDefinition.StandardTableMappings + }; + + var (ds, adapter) = await _fixture.CreateSchemaAdapterAsync("testorg", partitionDef, ct); + + await adapter.WriteAsync(new MeshNode("TestOrg") { Name = "Test Org", NodeType = "Markdown" }, _options, ct); + + await adapter.WriteAsync(new MeshNode("parent-thread", "TestOrg/_Thread") + { + Name = "Parent Thread", NodeType = "Thread", MainNode = "TestOrg", + Content = new MeshThread() + }, _options, ct); + + await adapter.WriteAsync(new MeshNode("msg1", "TestOrg/_Thread/parent-thread") + { + Name = "Response", NodeType = "ThreadMessage", MainNode = "TestOrg", + Content = new MeshWeaver.AI.ThreadMessage { Role = "assistant", Text = "..." } + }, _options, ct); + + await adapter.WriteAsync(new MeshNode("sub-thread", "TestOrg/_Thread/parent-thread/msg1") + { + Name = "Sub Thread", NodeType = "Thread", MainNode = "TestOrg", + Content = new MeshThread() + }, _options, ct); + + // Ask for a path DEEPER than the sub-thread (e.g., a message in the sub-thread) + // FindBestPrefixMatch should find the sub-thread as the deepest match + var (match, segments) = await adapter.FindBestPrefixMatchAsync( + "TestOrg/_Thread/parent-thread/msg1/sub-thread/sub-msg1", _options, ct); + + match.Should().NotBeNull("should find sub-thread as best prefix for deeper path"); + match!.Path.Should().Be("TestOrg/_Thread/parent-thread/msg1/sub-thread"); + segments.Should().Be(5); + } +} diff --git a/test/MeshWeaver.Hosting.PostgreSql.Test/UserActivityCrossPartitionTests.cs b/test/MeshWeaver.Hosting.PostgreSql.Test/UserActivityCrossPartitionTests.cs index b6bd9f6da..1e13cb9f1 100644 --- a/test/MeshWeaver.Hosting.PostgreSql.Test/UserActivityCrossPartitionTests.cs +++ b/test/MeshWeaver.Hosting.PostgreSql.Test/UserActivityCrossPartitionTests.cs @@ -180,6 +180,66 @@ public async Task Threads_NotInCrossSchemaStoredProc() "Threads are in satellite tables — stored proc only searches mesh_nodes"); } + [Fact(Timeout = 60000)] + public async Task Threads_FoundViaCrossSchemaUnionOnSatelliteTable() + { + var ct = TestContext.Current.CancellationToken; + await SetupMultiOrgWithThreadsAsync(ct); + + // First verify without access control (no userId) — confirms data is there + var schemas = new List { "orga", "orgb" }; + var generator = new PostgreSqlSqlGenerator(); + var query = new QueryParser().Parse("nodeType:Thread scope:subtree"); + var (sqlNoAc, paramsNoAc) = generator.GenerateCrossSchemaSelectQuery( + query, schemas, userId: null, tableName: "threads"); + + var noAcResults = new List(); + await using (var cmd = _fixture.DataSource.CreateCommand(sqlNoAc)) + { + foreach (var (name, value) in paramsNoAc) + cmd.Parameters.Add(new NpgsqlParameter(name, value ?? DBNull.Value)); + await using var reader = await cmd.ExecuteReaderAsync(ct); + while (await reader.ReadAsync(ct)) + { + var id = reader.GetString(0); + var ns = reader.IsDBNull(1) ? null : reader.GetString(1); + noAcResults.Add(new MeshNode(id, string.IsNullOrEmpty(ns) ? null : ns) + { + Name = reader.IsDBNull(2) ? null : reader.GetString(2), + NodeType = reader.IsDBNull(3) ? null : reader.GetString(3), + }); + } + } + noAcResults.Should().HaveCount(2, "data should exist in both schemas (no access control)"); + + // Now with access control — testuser should see threads via partition_access + UEP + var generator2 = new PostgreSqlSqlGenerator(); + var (sql, parameters) = generator2.GenerateCrossSchemaSelectQuery( + query, schemas, userId: "testuser", tableName: "threads"); + + var results = new List(); + await using (var cmd = _fixture.DataSource.CreateCommand(sql)) + { + foreach (var (name, value) in parameters) + cmd.Parameters.Add(new NpgsqlParameter(name, value ?? DBNull.Value)); + await using var reader = await cmd.ExecuteReaderAsync(ct); + while (await reader.ReadAsync(ct)) + { + var id = reader.GetString(0); + var ns = reader.IsDBNull(1) ? null : reader.GetString(1); + results.Add(new MeshNode(id, string.IsNullOrEmpty(ns) ? null : ns) + { + Name = reader.IsDBNull(2) ? null : reader.GetString(2), + NodeType = reader.IsDBNull(3) ? null : reader.GetString(3), + }); + } + } + + results.Should().HaveCount(2, "should find threads from both orgs via UNION ALL on threads table"); + results.Should().Contain(n => n.Name == "Discussion in OrgA"); + results.Should().Contain(n => n.Name == "Discussion in OrgB"); + } + [Fact(Timeout = 60000)] public async Task MainNodes_VisibleInCrossSchemaStoredProc() { diff --git a/test/MeshWeaver.NodeOperations.Test/ApiTokenAccessTest.cs b/test/MeshWeaver.NodeOperations.Test/ApiTokenAccessTest.cs new file mode 100644 index 000000000..b16c2c1ed --- /dev/null +++ b/test/MeshWeaver.NodeOperations.Test/ApiTokenAccessTest.cs @@ -0,0 +1,104 @@ +using System; +using System.Linq; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Hosting.Monolith.TestBase; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace MeshWeaver.NodeOperations.Test; + +/// +/// Tests for ApiToken creation via standard CreateNodeRequest. +/// ApiToken is a satellite of User — stored at User/{userId}/_Api/{hashPrefix} +/// with MainNode pointing to User/{userId}. +/// Access is controlled by Permission.Api (mapped in GetPermissionForNodeType). +/// Same pattern as Thread (Permission.Thread) and Comment (Permission.Comment). +/// +public class ApiTokenAccessTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => base.ConfigureMesh(builder) + .AddSampleUsers(); + + [Fact] + public async Task CreateApiToken_ViaCreateNodeRequest_Succeeds() + { + var ct = new CancellationTokenSource(10.Seconds()).Token; + + // Generate token hash + var rawToken = $"mw_{Convert.ToHexString(RandomNumberGenerator.GetBytes(32)).ToLowerInvariant()}"; + var hash = ValidateTokenRequest.HashToken(rawToken); + var hashPrefix = hash[..12]; + + // Create token as satellite of User node — same pattern as Thread + var userId = "rbuergi"; + var tokenNode = new MeshNode(hashPrefix, $"User/{userId}/_Api") + { + Name = "Test API Token", + NodeType = ApiTokenNodeType.NodeType, + MainNode = $"User/{userId}", + Content = new ApiToken + { + UserId = userId, + UserName = "Roland", + UserEmail = "rbuergi@systemorph.com", + TokenHash = hash, + Label = "Test Token", + CreatedAt = DateTimeOffset.UtcNow, + } + }; + + // Act — standard CreateNodeRequest + var created = await NodeFactory.CreateNodeAsync(tokenNode, ct); + + // Assert + created.Should().NotBeNull(); + created.Path.Should().Be($"User/{userId}/_Api/{hashPrefix}"); + created.NodeType.Should().Be(ApiTokenNodeType.NodeType); + created.MainNode.Should().Be($"User/{userId}"); + Output.WriteLine($"Token created at {created.Path}"); + } + + [Fact] + public async Task CreateApiToken_StoredUnderUserPath() + { + var ct = new CancellationTokenSource(10.Seconds()).Token; + + var hash = ValidateTokenRequest.HashToken("mw_test_token_12345"); + var hashPrefix = hash[..12]; + var userId = "rbuergi"; + + var tokenNode = new MeshNode(hashPrefix, $"User/{userId}/_Api") + { + Name = "Path Test Token", + NodeType = ApiTokenNodeType.NodeType, + MainNode = $"User/{userId}", + Content = new ApiToken + { + UserId = userId, + UserName = "Roland", + UserEmail = "rbuergi@systemorph.com", + TokenHash = hash, + Label = "Path Test", + CreatedAt = DateTimeOffset.UtcNow, + } + }; + + await NodeFactory.CreateNodeAsync(tokenNode, ct); + + // Verify via query + var result = await MeshQuery.QueryAsync($"path:User/{userId}/_Api/{hashPrefix}") + .FirstOrDefaultAsync(ct); + result.Should().NotBeNull("token should be retrievable by path"); + result!.MainNode.Should().Be($"User/{userId}"); + } +} diff --git a/test/MeshWeaver.NodeOperations.Test/MeshPluginAccessContextTest.cs b/test/MeshWeaver.NodeOperations.Test/MeshPluginAccessContextTest.cs new file mode 100644 index 000000000..887614e7b --- /dev/null +++ b/test/MeshWeaver.NodeOperations.Test/MeshPluginAccessContextTest.cs @@ -0,0 +1,126 @@ +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.AI.Persistence; +using MeshWeaver.Graph; +using MeshWeaver.Hosting.Monolith.TestBase; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Messaging; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace MeshWeaver.NodeOperations.Test; + +/// +/// Tests that MeshPlugin tool calls restore the user's access context. +/// In production, AsyncLocal doesn't flow through the AI framework's +/// async streaming + tool invocation chain, so the plugin must explicitly +/// restore it from ThreadExecutionContext.UserAccessContext. +/// +public class MeshPluginAccessContextTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => base.ConfigureMesh(builder) + .AddSampleUsers(); + + [Fact] + public async Task MeshPlugin_Get_RestoresAccessContext() + { + var ct = new CancellationTokenSource(10.Seconds()).Token; + + // Create a node + await CreateNodeAsync( + new MeshNode("test-doc", "User/rbuergi") { Name = "Test Doc", NodeType = "Markdown" }, + ct); + + // Simulate what happens during thread execution: + // 1. Set user context (normally done by ExecuteMessageAsync) + var accessService = Mesh.ServiceProvider.GetRequiredService(); + accessService.SetContext(new AccessContext { ObjectId = "rbuergi", Name = "Roland" }); + + // 2. Create plugin with a mock chat that has the execution context + var chat = new TestAgentChat + { + ExecutionContext = new ThreadExecutionContext + { + ThreadPath = "User/rbuergi/_Thread/test", + ResponseMessageId = "test-msg", + UserAccessContext = new AccessContext { ObjectId = "rbuergi", Name = "Roland" } + } + }; + var plugin = new MeshPlugin(Mesh, chat); + + // 3. Clear the AsyncLocal (simulates what happens when AI framework calls the tool) + accessService.SetContext(null); + + // 4. Call Get — should succeed because MeshPlugin restores context + var result = await plugin.Get("User/rbuergi/test-doc"); + result.Should().Contain("Test Doc", "MeshPlugin.Get should restore user context and return the node"); + Output.WriteLine($"Get result: {result[..System.Math.Min(200, result.Length)]}"); + } + + [Fact] + public async Task MeshPlugin_Update_RestoresAccessContext() + { + var ct = new CancellationTokenSource(10.Seconds()).Token; + + // Create a node + await CreateNodeAsync( + new MeshNode("update-test", "User/rbuergi") { Name = "Original", NodeType = "Markdown" }, + ct); + + var accessService = Mesh.ServiceProvider.GetRequiredService(); + var chat = new TestAgentChat + { + ExecutionContext = new ThreadExecutionContext + { + ThreadPath = "User/rbuergi/_Thread/test", + ResponseMessageId = "test-msg", + UserAccessContext = new AccessContext { ObjectId = "rbuergi", Name = "Roland" } + } + }; + var plugin = new MeshPlugin(Mesh, chat); + + // Clear AsyncLocal — simulates AI framework tool invocation + accessService.SetContext(null); + + // Update should succeed with restored context + var result = await plugin.Patch( + "User/rbuergi/update-test", + "{\"name\": \"Updated Name\"}"); + result.Should().Contain("Patched", "MeshPlugin.Patch should restore user context and update"); + Output.WriteLine($"Patch result: {result}"); + } + + /// + /// Minimal IAgentChat implementation for testing MeshPlugin access context. + /// + private class TestAgentChat : IAgentChat + { + public ThreadExecutionContext? ExecutionContext { get; set; } + public string? LastDelegationPath { get; set; } + public Action? UpdateDelegationStatus { get; set; } + public Action? ForwardToolCall { get; set; } + public AgentContext? Context { get; set; } + public void SetContext(AgentContext? applicationContext) => Context = applicationContext; + public void SetSelectedAgent(string? agentName) { } + public Task ResumeAsync(ChatConversation conversation) => Task.CompletedTask; + public Task> GetOrderedAgentsAsync() + => Task.FromResult>(new List()); + public async IAsyncEnumerable GetResponseAsync( + IReadOnlyCollection messages, [EnumeratorCancellation] CancellationToken ct = default) + { await Task.CompletedTask; yield break; } + public async IAsyncEnumerable GetStreamingResponseAsync( + IReadOnlyCollection messages, [EnumeratorCancellation] CancellationToken ct = default) + { await Task.CompletedTask; yield break; } + public void SetThreadId(string threadId) { } + public void DisplayLayoutArea(LayoutAreaControl layoutAreaControl) { } + } +} diff --git a/test/MeshWeaver.NodeOperations.Test/xunit.runner.json b/test/MeshWeaver.NodeOperations.Test/xunit.runner.json index b0ad92b58..c46ded3d8 100644 --- a/test/MeshWeaver.NodeOperations.Test/xunit.runner.json +++ b/test/MeshWeaver.NodeOperations.Test/xunit.runner.json @@ -2,5 +2,5 @@ "parallelizeAssembly": false, "parallelizeTestCollections": false, "maxParallelThreads": 1, - "methodTimeout": 120000 + "methodTimeout": 30000 } diff --git a/test/MeshWeaver.PathResolution.Test/AddressResolutionTest.cs b/test/MeshWeaver.PathResolution.Test/AddressResolutionTest.cs index 8f4296bcd..543501dd3 100644 --- a/test/MeshWeaver.PathResolution.Test/AddressResolutionTest.cs +++ b/test/MeshWeaver.PathResolution.Test/AddressResolutionTest.cs @@ -198,7 +198,6 @@ public async Task ResolvePath_ThreadMessageNode_ResolvesToFullMessagePath() Order = 1, Content = new ThreadMessage { - Id = "msg1", Role = "user", Text = "Hello", Timestamp = System.DateTime.UtcNow, @@ -241,7 +240,6 @@ public async Task ResolvePath_ThreadNode_ResolvesCorrectlyWithChildren() Order = 1, Content = new ThreadMessage { - Id = "m1", Role = "assistant", Text = "Response", Timestamp = System.DateTime.UtcNow, diff --git a/test/MeshWeaver.Security.Test/ThreadAccessTest.cs b/test/MeshWeaver.Security.Test/ThreadAccessTest.cs index 6d352c603..7561749c4 100644 --- a/test/MeshWeaver.Security.Test/ThreadAccessTest.cs +++ b/test/MeshWeaver.Security.Test/ThreadAccessTest.cs @@ -97,7 +97,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(threadPath) NodeType = ThreadMessageNodeType.NodeType, Content = new ThreadMessage { - Id = msgId, Role = "user", Text = "Hello!", Type = ThreadMessageType.ExecutedInput @@ -172,7 +171,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(threadPath) NodeType = ThreadMessageNodeType.NodeType, Content = new ThreadMessage { - Id = "attack-msg", Role = "user", Text = "Injected message", Type = ThreadMessageType.ExecutedInput diff --git a/test/MeshWeaver.Security.Test/ThreadStreamingIdentityTest.cs b/test/MeshWeaver.Security.Test/ThreadStreamingIdentityTest.cs index e23a36d69..777266505 100644 --- a/test/MeshWeaver.Security.Test/ThreadStreamingIdentityTest.cs +++ b/test/MeshWeaver.Security.Test/ThreadStreamingIdentityTest.cs @@ -204,6 +204,7 @@ public async Task SubmitMessage_StreamsIncrementally_NotAllAtOnce() "first streaming update should arrive within 5s — if it takes longer, " + "updates are blocked in the _Exec hub's message buffer (the bug we fixed)"); } + } /// diff --git a/test/MeshWeaver.Security.Test/UserPublicReadTest.cs b/test/MeshWeaver.Security.Test/UserPublicReadTest.cs index 4ef0e46c7..605ae9564 100644 --- a/test/MeshWeaver.Security.Test/UserPublicReadTest.cs +++ b/test/MeshWeaver.Security.Test/UserPublicReadTest.cs @@ -136,7 +136,7 @@ public async Task AuthenticatedUser_CanQuery_OrganizationNodes_ByNodeType() } [Fact(Timeout = 30000)] - public async Task DynamicallyCreated_OrganizationNode_IsPubliclyReadable() + public async Task DynamicallyCreated_OrganizationNode_RequiresPartitionAccess() { // Create an Organization dynamically (simulates runtime creation) var securityService = Mesh.ServiceProvider.GetRequiredService(); @@ -155,7 +155,7 @@ await securityService.AddUserRoleAsync("Creator", "Admin", null, "system", created.Should().NotBeNull(); Output.WriteLine($"Created: {created.Path}"); - // Now query as a different unprivileged user + // Unprivileged user cannot see the org (partition access controls visibility) LoginAsUnprivilegedUser(); var results = await MeshQuery.QueryAsync( @@ -163,7 +163,18 @@ await securityService.AddUserRoleAsync("Creator", "Admin", null, "system", ct: TestContext.Current.CancellationToken ).ToArrayAsync(TestContext.Current.CancellationToken); - results.Should().HaveCount(1, "Dynamically created Organization should be publicly readable"); - results[0].Name.Should().Be("Globex Corp"); + results.Should().BeEmpty("Organization instances require partition-level access, not public read"); + + // Grant Alice (the unprivileged user) Viewer role on Globex + await securityService.AddUserRoleAsync("Alice", "Viewer", "Globex", "system", + TestContext.Current.CancellationToken); + + var resultsAfterGrant = await MeshQuery.QueryAsync( + "path:Globex", + ct: TestContext.Current.CancellationToken + ).ToArrayAsync(TestContext.Current.CancellationToken); + + resultsAfterGrant.Should().HaveCount(1, "Organization should be readable after granting Viewer role"); + resultsAfterGrant[0].Name.Should().Be("Globex Corp"); } } diff --git a/test/MeshWeaver.Threading.Test/AccessContextToolCallTest.cs b/test/MeshWeaver.Threading.Test/AccessContextToolCallTest.cs new file mode 100644 index 000000000..8d7377668 --- /dev/null +++ b/test/MeshWeaver.Threading.Test/AccessContextToolCallTest.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Graph; +using MeshWeaver.Hosting.Monolith.TestBase; +using MeshWeaver.Mesh; +using MeshWeaver.Messaging; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace MeshWeaver.Threading.Test; + +/// +/// Tests that the AccessContextAIFunction wrapper restores user identity +/// before each tool invocation. Without this, tool calls during AI streaming +/// run without identity (AsyncLocal lost), causing "Access denied" errors. +/// +public class AccessContextToolCallTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => base.ConfigureMesh(builder) + .AddSampleUsers(); + + [Fact] + public async Task AccessContextAIFunction_RestoresIdentity_BeforeToolCall() + { + var ct = new CancellationTokenSource(10.Seconds()).Token; + var accessService = Mesh.ServiceProvider.GetRequiredService(); + + // Track what context the tool sees + AccessContext? capturedContext = null; + + // Create a simple AIFunction that captures the access context + var innerTool = AIFunctionFactory.Create( + (string input) => + { + capturedContext = accessService.Context; + return $"Got: {input}"; + }, + name: "test_tool", + description: "Test tool"); + + // Create a mock chat with execution context + var chat = new TestAgentChat + { + ExecutionContext = new ThreadExecutionContext + { + ThreadPath = "User/rbuergi/_Thread/test", + ResponseMessageId = "msg1", + UserAccessContext = new AccessContext { ObjectId = "rbuergi", Name = "Roland" } + } + }; + + // Wrap with AccessContextAIFunction + var wrapped = new AccessContextAIFunction( + (AIFunction)innerTool, chat, accessService); + + // Clear the AsyncLocal (simulates AI framework tool invocation context) + accessService.SetContext(null); + accessService.Context.Should().BeNull("context should be cleared before test"); + + // Invoke the wrapped tool + var result = await wrapped.InvokeAsync( + new AIFunctionArguments(new Dictionary { ["input"] = "hello" }), ct); + + // Verify the tool saw the restored context + capturedContext.Should().NotBeNull("tool should see restored access context"); + capturedContext!.ObjectId.Should().Be("rbuergi"); + Output.WriteLine($"Tool saw context: {capturedContext.ObjectId}"); + } + + [Fact] + public async Task AccessContextAIFunction_WithoutExecutionContext_DoesNotCrash() + { + var ct = new CancellationTokenSource(10.Seconds()).Token; + var accessService = Mesh.ServiceProvider.GetRequiredService(); + + var innerTool = AIFunctionFactory.Create( + (string input) => $"Got: {input}", + name: "test_tool", + description: "Test tool"); + + // Chat with no execution context + var chat = new TestAgentChat(); + + var wrapped = new AccessContextAIFunction( + (AIFunction)innerTool, chat, accessService); + + accessService.SetContext(null); + + // Should not throw + var result = await wrapped.InvokeAsync( + new AIFunctionArguments(new Dictionary { ["input"] = "hello" }), ct); + result.Should().NotBeNull(); + } + + [Fact] + public void DelegationDepthGuard_BlocksExcessiveNesting() + { + // Simulate a deeply nested thread path (depth 3 = 3 levels of _Thread) + var deepPath = "Org/Doc/_Thread/thread1/msg1/_Thread/sub1/msg2/_Thread/sub2"; + var depth = deepPath.Split("/_Thread/").Length - 1; + depth.Should().Be(3, "path has 3 _Thread segments"); + (depth >= 3).Should().BeTrue("delegation should be blocked at depth >= 3"); + } +} + +/// +/// Minimal IAgentChat for testing. +/// +file class TestAgentChat : IAgentChat +{ + public ThreadExecutionContext? ExecutionContext { get; set; } + public AgentContext? Context { get; set; } + public string? LastDelegationPath { get; set; } + public Action? UpdateDelegationStatus { get; set; } + public Action? ForwardToolCall { get; set; } + public void SetContext(AgentContext? ctx) => Context = ctx; + public void SetSelectedAgent(string? name) { } + public Task ResumeAsync(AI.Persistence.ChatConversation c) => Task.CompletedTask; + public Task> GetOrderedAgentsAsync() + => Task.FromResult>(new List()); + public async IAsyncEnumerable GetResponseAsync( + IReadOnlyCollection m, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct = default) + { await Task.CompletedTask; yield break; } + public async IAsyncEnumerable GetStreamingResponseAsync( + IReadOnlyCollection m, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct = default) + { await Task.CompletedTask; yield break; } + public void SetThreadId(string id) { } + public void DisplayLayoutArea(MeshWeaver.Layout.LayoutAreaControl c) { } +} diff --git a/test/MeshWeaver.Threading.Test/AutoExecuteFlowTest.cs b/test/MeshWeaver.Threading.Test/AutoExecuteFlowTest.cs new file mode 100644 index 000000000..af1873e88 --- /dev/null +++ b/test/MeshWeaver.Threading.Test/AutoExecuteFlowTest.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Graph; +using MeshWeaver.Hosting.Monolith.TestBase; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Threading.Test; + +/// +/// Tests the portal flow 1:1: +/// 1. Create thread via BuildThreadNode + CreateNodeRequest +/// 2. GUI creates user + response cells via CreateNodeRequest +/// 3. GUI sends SubmitMessageRequest with cell IDs +/// 4. Server executes, writes response to the response cell +/// +public class AutoExecuteFlowTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + private const string ContextPath = "User/TestUser"; + + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => base.ConfigureMesh(builder) + .ConfigureServices(services => + { + services.AddSingleton(new EchoChatClientFactory()); + return services; + }) + .AddAI() + .AddSampleUsers(); + + [Fact] + public async Task PortalFlow_CreateThread_CreateCells_Submit_ResponseWritten() + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = GetClient(); + + // Step 1: Create thread (BuildThreadNode — no PendingUserMessage) + var threadNode = ThreadNodeType.BuildThreadNode(ContextPath, "Hello portal flow!", "TestUser"); + var threadPath = threadNode.Path!; + Output.WriteLine($"Thread: {threadPath}"); + + var createResponse = await client.AwaitResponse( + new CreateNodeRequest(threadNode), + o => o.WithTarget(Mesh.Address), ct); + createResponse.Message.Success.Should().BeTrue(createResponse.Message.Error); + Output.WriteLine("Thread created"); + + // Step 2: GUI creates cells (thread exists now) + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + client.Post(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage + { + Role = "user", Text = "Hello portal flow!", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.ExecutedInput, CreatedBy = "TestUser" + } + }), o => o.WithTarget(new Address(threadPath))); + + client.Post(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage + { + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse, AgentName = "Orchestrator" + } + }), o => o.WithTarget(new Address(threadPath))); + + // Step 3: Submit with cell IDs + Output.WriteLine("Submitting message..."); + var submitResp = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, + UserMessageText = "Hello portal flow!", + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId, + AgentName = "Orchestrator", + ContextPath = ContextPath + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResp.Message.Success.Should().BeTrue(submitResp.Message.Error); + Output.WriteLine($"Submit response: Messages=[{string.Join(",", submitResp.Message.Messages ?? [])}]"); + + // Step 4: Wait for execution to complete + for (var i = 0; i < 60; i++) + { + var dataResp = await client.AwaitResponse( + new GetDataRequest(new MeshNodeReference()), + o => o.WithTarget(new Address(threadPath)), ct); + var node = dataResp.Message.Data as MeshNode; + if (node?.Content is JsonElement je) + node = node with { Content = je.Deserialize(Mesh.JsonSerializerOptions) }; + var thread = node?.Content as MeshThread; + + if (thread is { IsExecuting: false }) + { + Output.WriteLine($"Execution complete after {i * 500}ms"); + + // Verify response cell + var responsePath = $"{threadPath}/{responseMsgId}"; + var responseResp = await client.AwaitResponse( + new GetDataRequest(new MeshNodeReference()), + o => o.WithTarget(new Address(responsePath)), ct); + var rNode = responseResp.Message.Data as MeshNode; + if (rNode?.Content is JsonElement rje) + rNode = rNode with { Content = rje.Deserialize(Mesh.JsonSerializerOptions) }; + var responseMsg = rNode?.Content as ThreadMessage; + responseMsg.Should().NotBeNull(); + responseMsg!.Text.Should().NotBeNullOrEmpty("agent should have written response"); + Output.WriteLine($"Response: {responseMsg.Text[..Math.Min(80, responseMsg.Text.Length)]}"); + return; // SUCCESS + } + await Task.Delay(500, ct); + } + throw new TimeoutException("Execution did not complete"); + } + + [Fact] + public async Task PortalFlow_ResponseCell_GetsUpdatedByExecution() + { + var ct = new CancellationTokenSource(30.Seconds()).Token; + var client = GetClient(); + + var threadNode = ThreadNodeType.BuildThreadNode(ContextPath, "Test response update", "TestUser"); + var threadPath = threadNode.Path!; + + await client.AwaitResponse( + new CreateNodeRequest(threadNode), o => o.WithTarget(Mesh.Address), ct); + + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + var responsePath = $"{threadPath}/{responseMsgId}"; + + client.Post(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Test response update", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath))); + + client.Post(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath))); + + await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = "Test response update", + UserMessageId = userMsgId, ResponseMessageId = responseMsgId, ContextPath = ContextPath + }, o => o.WithTarget(new Address(threadPath)), ct); + + for (var i = 0; i < 60; i++) + { + var responseResp = await client.AwaitResponse( + new GetDataRequest(new MeshNodeReference()), + o => o.WithTarget(new Address(responsePath)), ct); + var rNode = responseResp.Message.Data as MeshNode; + if (rNode?.Content is JsonElement rje) + rNode = rNode with { Content = rje.Deserialize(Mesh.JsonSerializerOptions) }; + var msg = rNode?.Content as ThreadMessage; + if (msg?.Text is { Length: > 0 } text + && !text.StartsWith("Allocating") && !text.StartsWith("Loading") && !text.StartsWith("Generating")) + { + Output.WriteLine($"Response cell updated: {text[..Math.Min(80, text.Length)]}"); + return; + } + await Task.Delay(500, ct); + } + throw new TimeoutException("Response cell never got final text"); + } + + #region Echo LLM + + private class EchoChatClient : IChatClient + { + public ChatClientMetadata Metadata => new("EchoProvider"); + public Task GetResponseAsync(IEnumerable messages, ChatOptions? options = null, CancellationToken ct = default) + => Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, $"Echo: {messages.Count()} messages"))); + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken ct = default) + { + yield return new ChatResponseUpdate(ChatRole.Assistant, $"Echo: {messages.Count()} messages received."); + await Task.Delay(10, ct); + } + + public object? GetService(Type serviceType, object? key = null) => serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } + } + + private class EchoChatClientFactory : IChatClientFactory + { + public string Name => "EchoFactory"; + public IReadOnlyList Models => ["echo-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => new(chatClient: new EchoChatClient(), instructions: "Echo agent.", + name: config.Id, description: config.Description ?? "", + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync(AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); + } + + #endregion +} diff --git a/test/MeshWeaver.Threading.Test/BinaryAttachmentTest.cs b/test/MeshWeaver.Threading.Test/BinaryAttachmentTest.cs new file mode 100644 index 000000000..819413dc4 --- /dev/null +++ b/test/MeshWeaver.Threading.Test/BinaryAttachmentTest.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using FluentAssertions; +using Microsoft.Extensions.AI; +using Xunit; + +namespace MeshWeaver.Threading.Test; + +/// +/// Tests that the AzureClaudeChatClient correctly serializes DataContent +/// (PDFs, images) as base64 content blocks in the Claude API format. +/// +public class BinaryAttachmentTest +{ + [Fact] + public void DataContent_Pdf_SerializesAsDocumentBlock() + { + // Simulate a PDF file + var pdfBytes = new byte[] { 0x25, 0x50, 0x44, 0x46 }; // "%PDF" magic bytes + var dataContent = new DataContent(pdfBytes, "application/pdf"); + + // Verify DataContent properties + dataContent.MediaType.Should().Be("application/pdf"); + dataContent.Data.Length.Should().Be(4); + + // Verify base64 encoding + var base64 = Convert.ToBase64String(dataContent.Data.ToArray()); + base64.Should().Be("JVBERg=="); + + // Verify it's classified as "document" (not "image") + var type = dataContent.MediaType.StartsWith("image/") ? "image" : "document"; + type.Should().Be("document"); + } + + [Fact] + public void DataContent_Image_SerializesAsImageBlock() + { + // Simulate a PNG file (PNG magic bytes) + var pngBytes = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + var dataContent = new DataContent(pngBytes, "image/png"); + + dataContent.MediaType.Should().Be("image/png"); + + var type = dataContent.MediaType.StartsWith("image/") ? "image" : "document"; + type.Should().Be("image"); + } + + [Fact] + public void MixedContent_ChatMessage_ContainsTextAndBinary() + { + var pdfBytes = new byte[] { 0x25, 0x50, 0x44, 0x46 }; + var imageBytes = new byte[] { 0x89, 0x50, 0x4E, 0x47 }; + + var contents = new List + { + new TextContent("Analyze these documents:"), + new DataContent(pdfBytes, "application/pdf") { Name = "report.pdf" }, + new DataContent(imageBytes, "image/png") { Name = "chart.png" }, + new TextContent("What are the key findings?") + }; + + var message = new ChatMessage(ChatRole.User, contents); + + message.Contents.Should().HaveCount(4); + message.Contents[0].Should().BeOfType(); + message.Contents[1].Should().BeOfType(); + message.Contents[2].Should().BeOfType(); + message.Contents[3].Should().BeOfType(); + + var pdf = (DataContent)message.Contents[1]; + pdf.MediaType.Should().Be("application/pdf"); + pdf.Name.Should().Be("report.pdf"); + pdf.Data.Length.Should().Be(4); + } + + [Fact] + public void ClaudeContentBlock_WithSource_SerializesToCorrectJson() + { + // Simulate what AzureClaudeChatClient.BuildRequest produces + var pdfBytes = new byte[] { 0x25, 0x50, 0x44, 0x46 }; + var base64Data = Convert.ToBase64String(pdfBytes); + + var block = new + { + type = "document", + source = new + { + type = "base64", + media_type = "application/pdf", + data = base64Data + } + }; + + var json = JsonSerializer.Serialize(block, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower + }); + + json.Should().Contain("\"type\":\"document\""); + json.Should().Contain("\"media_type\":\"application/pdf\""); + json.Should().Contain("\"type\":\"base64\""); + json.Should().Contain($"\"data\":\"{base64Data}\""); + } + + [Fact] + public void BinaryExtensions_DetectedCorrectly() + { + var binaryExts = new HashSet(StringComparer.OrdinalIgnoreCase) + { + ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".tiff" + }; + + binaryExts.Contains(".pdf").Should().BeTrue(); + binaryExts.Contains(".PDF").Should().BeTrue(); + binaryExts.Contains(".png").Should().BeTrue(); + binaryExts.Contains(".md").Should().BeFalse(); + binaryExts.Contains(".txt").Should().BeFalse(); + binaryExts.Contains(".json").Should().BeFalse(); + } + + [Fact] + public void ContentPath_Parsing_ExtractsNodePathAndFileName() + { + // Local path: content:report.pdf + var path1 = "content:report.pdf"; + var idx1 = path1.IndexOf("content:", StringComparison.OrdinalIgnoreCase); + idx1.Should().Be(0); + var fileName1 = path1[(idx1 + "content:".Length)..]; + fileName1.Should().Be("report.pdf"); + + // Absolute path: OrgA/Doc/content:chart.png + var path2 = "OrgA/Doc/content:chart.png"; + var idx2 = path2.IndexOf("content:", StringComparison.OrdinalIgnoreCase); + idx2.Should().Be(9); // after "OrgA/Doc/" + var nodePath2 = path2[..(idx2 - 1)]; // strip trailing / + var fileName2 = path2[(idx2 + "content:".Length)..]; + nodePath2.Should().Be("OrgA/Doc"); + fileName2.Should().Be("chart.png"); + } +} diff --git a/test/MeshWeaver.Threading.Test/CancelThreadExecutionTest.cs b/test/MeshWeaver.Threading.Test/CancelThreadExecutionTest.cs index 701e53951..49ce43eaa 100644 --- a/test/MeshWeaver.Threading.Test/CancelThreadExecutionTest.cs +++ b/test/MeshWeaver.Threading.Test/CancelThreadExecutionTest.cs @@ -101,8 +101,23 @@ public async Task CancelStream_StopsExecutionAndMarksAsCancelled() var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Tell me a long story", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var submitResponse = await client.AwaitResponse( - new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Tell me a long story" }, + new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Tell me a long story", UserMessageId = userMsgId, ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); diff --git a/test/MeshWeaver.Threading.Test/ChatHistoryTest.cs b/test/MeshWeaver.Threading.Test/ChatHistoryTest.cs new file mode 100644 index 000000000..2521d4068 --- /dev/null +++ b/test/MeshWeaver.Threading.Test/ChatHistoryTest.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reactive.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Hosting.Monolith.TestBase; +using MeshWeaver.Graph; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Threading.Test; + +/// +/// Tests that ALL previous messages are passed to the agent on each execution. +/// The echo agent reports how many ChatMessage objects it received. +/// Message 1: agent sees 1 msg. Message 2: agent sees 3 msgs. Message 3: agent sees 5 msgs. +/// History is loaded from ThreadMessage nodes via GetDataRequest, not from a cached field. +/// +public class ChatHistoryTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + private const string ContextPath = "User/TestUser"; + + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => base.ConfigureMesh(builder) + .ConfigureServices(services => + { + services.AddSingleton(new EchoChatClientFactory()); + return services; + }) + .AddAI() + .AddSampleUsers(); + + private async Task CreateThreadAsync(IMessageHub client, string text, CancellationToken ct) + { + var threadNode = ThreadNodeType.BuildThreadNode(ContextPath, text, "TestUser"); + var response = await client.AwaitResponse( + new CreateNodeRequest(threadNode), + o => o.WithTarget(Mesh.Address), ct); + response.Message.Success.Should().BeTrue(response.Message.Error); + return response.Message.Node!.Path!; + } + + private async Task SubmitAndWait(IMessageHub client, string threadPath, string text, int expectedMsgCount, CancellationToken ct) + { + // GUI flow: create cells first, then submit + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = text, Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = text, ContextPath = ContextPath, + UserMessageId = userMsgId, ResponseMessageId = responseMsgId + }, o => o.WithTarget(new Address(threadPath)), ct); + + // Wait for execution to complete (Messages count reaches expected) + for (var i = 0; i < 60; i++) + { + var node = await MeshQuery.QueryAsync($"path:{threadPath}").FirstOrDefaultAsync(ct); + var thread = node?.Content as MeshThread; + if (thread is { IsExecuting: false } && thread.Messages.Count >= expectedMsgCount) + { + // Read the last response message + var lastMsgId = thread.Messages[^1]; + var msgNode = await MeshQuery.QueryAsync($"path:{threadPath}/{lastMsgId}").FirstOrDefaultAsync(ct); + var tmsg = msgNode?.Content as ThreadMessage; + if (tmsg?.Text is { Length: > 0 }) + return tmsg.Text; + } + await Task.Delay(200, ct); + } + throw new TimeoutException($"Execution did not complete for {threadPath}"); + } + + [Fact] + public async Task ThreeMessages_AgentSeesFullHistory() + { + var ct = new CancellationTokenSource(60.Seconds()).Token; + var client = GetClient(); + var threadPath = await CreateThreadAsync(client, "History test", ct); + + // Message 1: agent should see 1 message (just the user's) + var response1 = await SubmitAndWait(client, threadPath, "First message", 2, ct); + Output.WriteLine($"Response 1: {response1}"); + // ChatClientAgent adds system prompt as first message (+1 to all counts) + response1.Should().Contain("2 messages", "first message: system + user"); + + // Message 2: system + user1 + assistant1 + user2 = 4 + var response2 = await SubmitAndWait(client, threadPath, "Second message", 4, ct); + Output.WriteLine($"Response 2: {response2}"); + response2.Should().Contain("4 messages", "second message: system + 2 history + 1 new"); + + // Message 3: system + user1 + assistant1 + user2 + assistant2 + user3 = 6 + var response3 = await SubmitAndWait(client, threadPath, "Third message", 6, ct); + Output.WriteLine($"Response 3: {response3}"); + response3.Should().Contain("6 messages", "third message: system + 4 history + 1 new"); + } + + [Fact] + public async Task TwoMessages_NoDuplicates_CorrectRoles() + { + var ct = new CancellationTokenSource(60.Seconds()).Token; + var client = GetClient(); + var threadPath = await CreateThreadAsync(client, "Duplicate check", ct); + + // Message 1: "Hello" + var response1 = await SubmitAndWait(client, threadPath, "Hello", 2, ct); + Output.WriteLine($"Response 1: {response1}"); + // ChatClientAgent adds system prompt as first message + response1.Should().Contain("2 messages", "first call: system prompt + user message"); + + // Message 2: "World" + var response2 = await SubmitAndWait(client, threadPath, "World", 4, ct); + Output.WriteLine($"Response 2: {response2}"); + + // Agent should see 4 messages: system + Hello + assistant-response + World + response2.Should().Contain("4 messages", + "second call: system + 2 history (user+assistant) + 1 new user = 4 total"); + } + + #region Echo LLM — responds with message count to verify history is passed + + private class EchoChatClient : IChatClient + { + public ChatClientMetadata Metadata => new("EchoProvider"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken ct = default) + { + var count = messages.Count(); + return Task.FromResult(new ChatResponse( + new ChatMessage(ChatRole.Assistant, $"I received {count} messages in this conversation."))); + } + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken ct = default) + { + var msgList = messages.ToList(); + var summary = string.Join(" | ", msgList.Select((m, i) => + $"[{i}:{m.Role}:{(m.Text?.Length > 30 ? m.Text[..30] + "..." : m.Text)}]")); + yield return new ChatResponseUpdate(ChatRole.Assistant, + $"I received {msgList.Count} messages in this conversation. Messages: {summary}"); + await Task.Delay(10, ct); + } + + public object? GetService(Type serviceType, object? key = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } + } + + private class EchoChatClientFactory : IChatClientFactory + { + public string Name => "EchoFactory"; + public IReadOnlyList Models => ["echo-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => new(chatClient: new EchoChatClient(), instructions: "Echo agent.", + name: config.Id, description: config.Description ?? "", + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); + } + + #endregion +} diff --git a/test/MeshWeaver.Threading.Test/DelegationExecutionTest.cs b/test/MeshWeaver.Threading.Test/DelegationExecutionTest.cs index bb04a0d44..8eadcf36b 100644 --- a/test/MeshWeaver.Threading.Test/DelegationExecutionTest.cs +++ b/test/MeshWeaver.Threading.Test/DelegationExecutionTest.cs @@ -74,7 +74,22 @@ public async Task DelegationSubThread_SubmitMessage_ProducesNavigableHierarchy() var threadPath = await CreateThreadAsync(client, "Delegation execution test", ct); Output.WriteLine($"Parent thread: {threadPath}"); - // 2. Submit a message to the parent thread (creates user + response messages) + // 2. Create cells and submit a message to the parent thread + var parentUserMsgId = Guid.NewGuid().ToString("N")[..8]; + var parentResponseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(parentUserMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Research reinsurance pricing", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(parentResponseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var parentMessages = client.GetWorkspace() .GetRemoteStream(new Address(threadPath))! .Select(nodes => GetMessages(nodes, threadPath)) @@ -85,7 +100,9 @@ public async Task DelegationSubThread_SubmitMessage_ProducesNavigableHierarchy() { ThreadPath = threadPath, UserMessageText = "Research reinsurance pricing", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = parentUserMsgId, + ResponseMessageId = parentResponseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); @@ -111,8 +128,23 @@ await NodeFactory.CreateNodeAsync(new MeshNode(subThreadId, parentMsgPath) }, ct); Output.WriteLine($"Sub-thread created: {subThreadPath}"); - // 5. Submit message to the sub-thread via SubmitMessageRequest + // 5. Create cells and submit message to the sub-thread via SubmitMessageRequest // This goes through the full ThreadExecution pipeline. + var subUserMsgId = Guid.NewGuid().ToString("N")[..8]; + var subResponseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(subUserMsgId, subThreadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Find documents about reinsurance pricing models", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(subThreadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(subResponseMsgId, subThreadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(subThreadPath)), ct); + var subMessages = client.GetWorkspace() .GetRemoteStream(new Address(subThreadPath))! .Select(nodes => GetMessages(nodes, subThreadPath)) @@ -123,7 +155,9 @@ await NodeFactory.CreateNodeAsync(new MeshNode(subThreadId, parentMsgPath) { ThreadPath = subThreadPath, UserMessageText = "Find documents about reinsurance pricing models", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = subUserMsgId, + ResponseMessageId = subResponseMsgId }, o => o.WithTarget(new Address(subThreadPath)), ct); subSubmitResponse.Message.Success.Should().BeTrue(subSubmitResponse.Message.Error); diff --git a/test/MeshWeaver.Threading.Test/DelegationFailureTest.cs b/test/MeshWeaver.Threading.Test/DelegationFailureTest.cs new file mode 100644 index 000000000..6328e7a44 --- /dev/null +++ b/test/MeshWeaver.Threading.Test/DelegationFailureTest.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using FluentAssertions.Extensions; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Graph; +using MeshWeaver.Hosting.Monolith.TestBase; +using MeshWeaver.Layout; +using MeshWeaver.Mesh; +using MeshWeaver.Messaging; +using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Threading.Test; + +/// +/// Tests that delegation failures are properly propagated: +/// - When sub-thread creation fails, the delegation returns an error result +/// - When CancellationToken fires, the delegation completes with failure +/// - The parent thread doesn't hang forever on broken delegations +/// +public class DelegationFailureTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + private const string ContextPath = "User/Roland"; + + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + { + return base.ConfigureMesh(builder) + .ConfigureServices(services => + { + // Use a slow agent that delegates — the delegation target won't exist + services.AddSingleton(new DelegatingFakeChatClientFactory()); + return services; + }) + .AddAI() + .AddSampleUsers(); + } + + protected override MessageHubConfiguration ConfigureClient(MessageHubConfiguration configuration) + { + configuration.TypeRegistry.AddAITypes(); + return base.ConfigureClient(configuration) + .AddLayoutClient(); + } + + private async Task CreateThreadAsync(IMessageHub client, string text, CancellationToken ct) + { + var threadNode = ThreadNodeType.BuildThreadNode(ContextPath, text, "Roland"); + var delivery = client.Post(new CreateNodeRequest(threadNode), + o => o.WithTarget(Mesh.Address))!; + var response = await client.RegisterCallback(delivery, (d, _) => Task.FromResult(d), ct); + var createResponse = ((IMessageDelivery)response).Message; + createResponse.Success.Should().BeTrue(createResponse.Error); + return createResponse.Node!.Path!; + } + + [Fact] + public async Task SubmitMessage_WithCancellation_DoesNotHangForever() + { + // This test verifies that when a thread is cancelled, the delegation + // doesn't hang indefinitely waiting for a sub-thread response. + var ct = new CancellationTokenSource(15.Seconds()).Token; + var client = GetClient(); + + var threadPath = await CreateThreadAsync(client, "Cancellation test", ct); + + // Create cells before submitting (GUI flow) + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Do something that delegates", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + + // Submit a message — the fake agent will try to delegate + var submitResponse = await client.AwaitResponse( + new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = "Do something that delegates", + UserMessageId = userMsgId, ResponseMessageId = responseMsgId + }, + o => o.WithTarget(new Address(threadPath)), ct); + submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); + + // Wait a bit for delegation to start + await Task.Delay(1000, ct); + + // Cancel the execution + client.Post(new CancelThreadStreamRequest { ThreadPath = threadPath }, + o => o.WithTarget(new Address(threadPath))); + + // Wait for execution to stop — should not hang + var workspace = client.GetWorkspace(); + var messagesStream = workspace.GetRemoteStream(new Address(threadPath))! + .Select(nodes => + { + var node = nodes?.FirstOrDefault(n => n.Path == threadPath); + return node?.Content as MeshThread; + }); + + // The thread should eventually have 2 messages (user + response) + // and the response should be marked as not executing + var thread = await messagesStream + .Where(t => t?.Messages.Count >= 2) + .Timeout(10.Seconds()) + .FirstAsync(); + + thread.Should().NotBeNull(); + Output.WriteLine($"Thread has {thread!.Messages.Count} messages"); + } + + #region Fake delegating agent + + /// + /// Agent that always tries to delegate to a non-existent "Worker" agent. + /// This simulates the failure case where delegation routing fails. + /// + private class DelegatingFakeChatClient : IChatClient + { + public ChatClientMetadata Metadata => new("DelegatingFake"); + + public Task GetResponseAsync( + IEnumerable messages, ChatOptions? options = null, + CancellationToken cancellationToken = default) + => Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, "Done"))); + + public async IAsyncEnumerable GetStreamingResponseAsync( + IEnumerable messages, ChatOptions? options = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + // Yield a function call to delegate_to_Worker + yield return new ChatResponseUpdate(ChatRole.Assistant, + [new FunctionCallContent("call1", "delegate_to_Worker", + new Dictionary { ["task"] = "Do some work" })]); + + // Wait for the tool result (the framework will invoke the delegation) + await Task.Delay(100, cancellationToken); + yield return new ChatResponseUpdate(ChatRole.Assistant, "Delegation completed."); + } + + public object? GetService(Type serviceType, object? serviceKey = null) => + serviceType == typeof(IChatClient) ? this : null; + public void Dispose() { } + } + + private class DelegatingFakeChatClientFactory : IChatClientFactory + { + public string Name => "DelegatingFakeFactory"; + public IReadOnlyList Models => ["fake-model"]; + public int Order => 0; + + public ChatClientAgent CreateAgent( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => new(chatClient: new DelegatingFakeChatClient(), + instructions: config.Instructions ?? "You delegate everything.", + name: config.Id, description: config.Description ?? config.Id, + tools: [], loggerFactory: null, services: null); + + public Task CreateAgentAsync( + AgentConfiguration config, IAgentChat chat, + IReadOnlyDictionary existingAgents, + IReadOnlyList hierarchyAgents, + string? modelName = null) + => Task.FromResult(CreateAgent(config, chat, existingAgents, hierarchyAgents, modelName)); + } + + #endregion +} diff --git a/test/MeshWeaver.Threading.Test/DelegationSubThreadTest.cs b/test/MeshWeaver.Threading.Test/DelegationSubThreadTest.cs index 1a36019a0..8534d72a9 100644 --- a/test/MeshWeaver.Threading.Test/DelegationSubThreadTest.cs +++ b/test/MeshWeaver.Threading.Test/DelegationSubThreadTest.cs @@ -61,7 +61,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) NodeType = ThreadMessageNodeType.NodeType, Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "Delegating to Worker...", Type = ThreadMessageType.AgentResponse, @@ -126,7 +125,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) NodeType = ThreadMessageNodeType.NodeType, Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "Working on it...", Type = ThreadMessageType.AgentResponse, @@ -159,7 +157,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(inputId, subThreadPath) NodeType = ThreadMessageNodeType.NodeType, Content = new ThreadMessage { - Id = inputId, Role = "user", Text = "Research the topic of reinsurance pricing", Type = ThreadMessageType.ExecutedInput @@ -172,7 +169,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(outputId, subThreadPath) NodeType = ThreadMessageNodeType.NodeType, Content = new ThreadMessage { - Id = outputId, Role = "assistant", Text = "Found 3 relevant documents about reinsurance pricing.", Type = ThreadMessageType.AgentResponse, @@ -334,12 +330,10 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) NodeType = ThreadMessageNodeType.NodeType, Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "Here's the plan. Delegating research...", Type = ThreadMessageType.AgentResponse, - AgentName = "Orchestrator", - DelegationPath = $"{threadPath}/{responseMsgId}/research-task-xyz1" + AgentName = "Orchestrator" } }, ct); @@ -363,10 +357,8 @@ await NodeFactory.CreateNodeAsync( .ToListAsync(ct); subThreads.Should().ContainSingle(); - // Verify: Response message has DelegationPath pointing to sub-thread + // Verify: Sub-thread is accessible under response message namespace var respNode = await MeshQuery.QueryAsync($"path:{threadPath}/{responseMsgId}").FirstOrDefaultAsync(ct); - var respMsg = respNode?.Content as ThreadMessage; - respMsg.Should().NotBeNull(); - respMsg!.DelegationPath.Should().Contain("research-task-xyz1"); + respNode.Should().NotBeNull(); } } diff --git a/test/MeshWeaver.Threading.Test/ExecuteThreadMessageTest.cs b/test/MeshWeaver.Threading.Test/ExecuteThreadMessageTest.cs index d554ee021..85f1ad9ea 100644 --- a/test/MeshWeaver.Threading.Test/ExecuteThreadMessageTest.cs +++ b/test/MeshWeaver.Threading.Test/ExecuteThreadMessageTest.cs @@ -105,8 +105,23 @@ public async Task SubmitMessage_CreatesUserAndResponseNodes() var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Hello agent", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var submitResponse = await client.AwaitResponse( - new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Hello agent" }, + new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Hello agent", UserMessageId = userMsgId, ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); @@ -145,18 +160,48 @@ public async Task SubmitMessage_SecondMessage_AccumulatesMessages() var messagesStream = ObserveMessages(client, threadPath); // 2. First message + var userMsgId1 = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId1 = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId1, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "First", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId1, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var twoMessages = messagesStream.Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); var r1 = await client.AwaitResponse( - new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "First" }, + new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "First", UserMessageId = userMsgId1, ResponseMessageId = responseMsgId1 }, o => o.WithTarget(new Address(threadPath)), ct); r1.Message.Success.Should().BeTrue(r1.Message.Error); var firstIds = await twoMessages; Output.WriteLine($"First batch: [{string.Join(", ", firstIds)}]"); // 3. Second message + var userMsgId2 = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId2 = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId2, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Second", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId2, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var fourMessages = messagesStream.Where(ids => ids.Count >= 4).FirstAsync().ToTask(ct); var r2 = await client.AwaitResponse( - new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Second" }, + new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Second", UserMessageId = userMsgId2, ResponseMessageId = responseMsgId2 }, o => o.WithTarget(new Address(threadPath)), ct); r2.Message.Success.Should().BeTrue(r2.Message.Error); var allIds = await fourMessages; @@ -187,8 +232,23 @@ public async Task SubmitMessage_BothNodesGetCorrectContentViaGetDataRequest() var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Tell me something", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var response = await client.AwaitResponse( - new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Tell me something" }, + new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Tell me something", UserMessageId = userMsgId, ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); response.Message.Success.Should().BeTrue(response.Message.Error); @@ -240,8 +300,24 @@ public async Task SubmitMessage_DoesNotDeadlock_ResponseWithin5Seconds() var client = GetClient(); var threadPath = await CreateThreadAsync(client, "Deadlock test", ct); + + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Quick test", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var response = await client.AwaitResponse( - new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Quick test" }, + new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Quick test", UserMessageId = userMsgId, ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); response.Message.Success.Should().BeTrue("SubmitMessageResponse should arrive without deadlock"); @@ -346,13 +422,30 @@ public async Task EndToEnd_SubmitChat_FullGuiDataFlow() var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); - // 4. Submit message + // 4. Create cells and submit message + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Hello from end-to-end test", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var submitResponse = await client.AwaitResponse( new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Hello from end-to-end test", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); diff --git a/test/MeshWeaver.Threading.Test/MeshNodeReferenceSingleInstanceTest.cs b/test/MeshWeaver.Threading.Test/MeshNodeReferenceSingleInstanceTest.cs index cb08e8b63..29a445131 100644 --- a/test/MeshWeaver.Threading.Test/MeshNodeReferenceSingleInstanceTest.cs +++ b/test/MeshWeaver.Threading.Test/MeshNodeReferenceSingleInstanceTest.cs @@ -270,13 +270,13 @@ await NodeFactory.CreateNodeAsync( Output.WriteLine($"Created sub-thread at: {subThreadPath}"); subThreadPath.Should().StartWith($"{threadPath}/"); - subThreadPath.Should().Contain($"/{ThreadNodeType.ThreadPartition}/"); + // Sub-threads under a parent that's already inside _Thread don't get + // another _Thread partition — BuildThreadNode skips nested _Thread. - // 4. Verify the sub-thread is queryable with the same query ThreadsCatalog uses - // ThreadsCatalog queries: namespace:{hubPath}/_Thread nodeType:Thread + // 4. Verify the sub-thread is queryable — lives directly under the parent thread namespace var meshQuery = Mesh.ServiceProvider.GetRequiredService(); var threads = await meshQuery.QueryAsync( - $"namespace:{threadPath}/{ThreadNodeType.ThreadPartition} nodeType:{ThreadNodeType.NodeType}").ToListAsync(ct); + $"namespace:{threadPath} nodeType:{ThreadNodeType.NodeType}").ToListAsync(ct); threads.Should().ContainSingle("should find the created sub-thread"); threads[0].Path.Should().Be(subThreadPath); diff --git a/test/MeshWeaver.Threading.Test/MeshWeaver.Threading.Test.csproj b/test/MeshWeaver.Threading.Test/MeshWeaver.Threading.Test.csproj index 13f363304..e9df02495 100644 --- a/test/MeshWeaver.Threading.Test/MeshWeaver.Threading.Test.csproj +++ b/test/MeshWeaver.Threading.Test/MeshWeaver.Threading.Test.csproj @@ -3,6 +3,9 @@ $(NoWarn);xUnit1051 + + + diff --git a/test/MeshWeaver.Threading.Test/StreamingAreaTest.cs b/test/MeshWeaver.Threading.Test/StreamingAreaTest.cs index 6733e80a7..afa62a550 100644 --- a/test/MeshWeaver.Threading.Test/StreamingAreaTest.cs +++ b/test/MeshWeaver.Threading.Test/StreamingAreaTest.cs @@ -89,7 +89,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) MainNode = "User/Roland", Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "Working on it...", Type = ThreadMessageType.AgentResponse, @@ -144,7 +143,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) MainNode = "User/Roland", Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "Done.", Type = ThreadMessageType.AgentResponse diff --git a/test/MeshWeaver.Threading.Test/StreamingRecursionTest.cs b/test/MeshWeaver.Threading.Test/StreamingRecursionTest.cs new file mode 100644 index 000000000..c1f8a62fc --- /dev/null +++ b/test/MeshWeaver.Threading.Test/StreamingRecursionTest.cs @@ -0,0 +1,86 @@ +using System.Collections.Immutable; +using System.Linq; +using FluentAssertions; +using MeshWeaver.AI; +using MeshWeaver.Layout; +using MeshWeaver.Layout.Composition; +using Xunit; + +namespace MeshWeaver.Threading.Test; + +/// +/// Tests that StreamingCompact does NOT recursively embed sub-thread LayoutAreaControls. +/// The recursive embed caused stack overflow when delegation sub-threads didn't exist +/// (each failed grain activation triggered another embed attempt). +/// +public class StreamingRecursionTest +{ + [Fact] + public void ToolCalls_WithDelegationPath_DoNotEmbed_LayoutAreaControl() + { + // A ThreadMessage with delegation tool calls (simulates streaming state) + var msg = new ThreadMessage + { + Role = "assistant", + Text = "Delegating...", + ToolCalls = + [ + new ToolCallEntry + { + Name = "delegate_to_agent", + DisplayName = "Delegating to Executor", + DelegationPath = "Org/_Thread/parent/msg1/sub-thread", + Result = null // In-progress — this was the trigger for recursive embed + }, + new ToolCallEntry + { + Name = "delegate_to_agent", + DisplayName = "Completed delegation", + DelegationPath = "Org/_Thread/parent/msg2/other-sub", + Result = "Done", + IsSuccess = true + } + ] + }; + + // The StreamingCompact view should NOT contain any LayoutAreaControl references + // It should only have static HTML links for delegation paths + // We verify by checking that the ToolCalls with DelegationPath don't trigger embedding + + // Verify the delegation entries exist + var delegations = msg.ToolCalls.Where(tc => !string.IsNullOrEmpty(tc.DelegationPath)).ToList(); + delegations.Should().HaveCount(2); + + // The in-progress delegation (Result == null) must NOT trigger recursive rendering + var inProgress = delegations.Where(tc => tc.Result == null).ToList(); + inProgress.Should().HaveCount(1); + + // Verify the fix: in-progress delegations should be rendered as static links, + // NOT as LayoutAreaControl(delegationPath, "Streaming") + // This is a design constraint test — the actual rendering is in StreamingCompact + // but we verify the data model doesn't force recursion + inProgress[0].DelegationPath.Should().NotBeNull(); + inProgress[0].Result.Should().BeNull("in-progress delegation has no result yet"); + + // The key invariant: no LayoutAreaControl should be created for delegation paths + // This is enforced by the code change in ThreadMessageLayoutAreas.StreamingCompact + // which now renders static links instead of recursive embeds + } + + [Fact] + public void ThreadMessage_ToolCalls_AreImmutableList() + { + // Verify tool calls use ImmutableList (no mutable collections) + var msg = new ThreadMessage + { + Role = "assistant", + Text = "", + ToolCalls = ImmutableList.Empty + .Add(new ToolCallEntry { Name = "get", DisplayName = "Get" }) + .Add(new ToolCallEntry { Name = "update", DisplayName = "Update" }) + }; + + msg.ToolCalls.Should().BeAssignableTo>(); + msg.ToolCalls.Should().HaveCount(2); + } +} diff --git a/test/MeshWeaver.Threading.Test/ThreadCreationTest.cs b/test/MeshWeaver.Threading.Test/ThreadCreationTest.cs index 488db0084..7dc000174 100644 --- a/test/MeshWeaver.Threading.Test/ThreadCreationTest.cs +++ b/test/MeshWeaver.Threading.Test/ThreadCreationTest.cs @@ -181,7 +181,6 @@ public async Task CreateThread_WithMessageAsChildNode_Succeeds() var messagePath = $"{threadPath}/{messageId}"; var messageContent = new ThreadMessage { - Id = messageId, Role = "user", Text = "Hello, world!", Timestamp = DateTime.UtcNow, @@ -387,7 +386,6 @@ public void ThreadMessages_ToChatMessages_ConvertsCorrectly() { new ThreadMessage { - Id = "1", Role = "user", Text = "Hello", AuthorName = "Alice", @@ -396,7 +394,6 @@ public void ThreadMessages_ToChatMessages_ConvertsCorrectly() }, new ThreadMessage { - Id = "2", Role = "assistant", Text = "Hi there!", AuthorName = "Bot", @@ -426,7 +423,6 @@ public void ThreadMessages_ToChatMessages_ExcludesEditingPrompts() { new ThreadMessage { - Id = "1", Role = "user", Text = "Submitted message", Timestamp = DateTime.UtcNow, @@ -434,7 +430,6 @@ public void ThreadMessages_ToChatMessages_ExcludesEditingPrompts() }, new ThreadMessage { - Id = "2", Role = "user", Text = "Currently typing...", Timestamp = DateTime.UtcNow, @@ -442,7 +437,6 @@ public void ThreadMessages_ToChatMessages_ExcludesEditingPrompts() }, new ThreadMessage { - Id = "3", Role = "assistant", Text = "Response", Timestamp = DateTime.UtcNow, @@ -465,7 +459,6 @@ public void ThreadMessage_DefaultType_IsExecutedInput() // Arrange & Act var message = new ThreadMessage { - Id = "1", Role = "user", Text = "Hello" }; @@ -494,16 +487,16 @@ public async Task CreateThreadMessage_WithDifferentTypes_PreservesType() await NodeFactory.CreateNodeAsync(threadNode, longTimeout); // Create a single message to test type preservation (simplify test) + var responseMessageId = Guid.NewGuid().AsString(); var responseMessage = new ThreadMessage { - Id = Guid.NewGuid().AsString(), Role = "assistant", Text = "Response", Type = ThreadMessageType.AgentResponse }; // Act - Create message node - var responseNode = new MeshNode($"{threadPath}/{responseMessage.Id}") + var responseNode = new MeshNode($"{threadPath}/{responseMessageId}") { NodeType = ThreadMessageNodeType.NodeType, Content = responseMessage diff --git a/test/MeshWeaver.Threading.Test/ThreadExecutionPersistenceTest.cs b/test/MeshWeaver.Threading.Test/ThreadExecutionPersistenceTest.cs index 7719e5313..4258ae42f 100644 --- a/test/MeshWeaver.Threading.Test/ThreadExecutionPersistenceTest.cs +++ b/test/MeshWeaver.Threading.Test/ThreadExecutionPersistenceTest.cs @@ -83,6 +83,33 @@ private IObservable> ObserveMessages(IMessageHub client, s }); } + private async Task<(string UserMsgId, string ResponseMsgId)> CreateCellsAndSubmitAsync( + IMessageHub client, string threadPath, string text, string contextPath, CancellationToken ct) + { + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = contextPath, + Content = new ThreadMessage { Role = "user", Text = text, Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = contextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = text, ContextPath = contextPath, + UserMessageId = userMsgId, ResponseMessageId = responseMsgId + }, o => o.WithTarget(new Address(threadPath)), ct); + + return (userMsgId, responseMsgId); + } + /// /// Verifies the full execution flow: /// 1. Create context → create thread → submit message @@ -106,21 +133,22 @@ public async Task ExecuteThread_PersistsToCorrectPartition() var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); - client.Post(new SubmitMessageRequest - { - ThreadPath = threadPath, - UserMessageText = "Hello from persistence test", - ContextPath = ContextPath - }, o => o.WithTarget(new Address(threadPath))); + await CreateCellsAndSubmitAsync(client, threadPath, "Hello from persistence test", ContextPath, ct); var msgIds = await twoMessages; msgIds.Should().HaveCount(2); Output.WriteLine($"Messages: [{string.Join(", ", msgIds)}]"); - // Verify nodes exist in persistence (created by meshService.CreateNodeAsync) + // Verify nodes exist in persistence — cells are created in background, + // so retry briefly until they appear. var userMsgPath = $"{threadPath}/{msgIds[0]}"; - var userNode = await MeshQuery.QueryAsync($"path:{userMsgPath}") - .FirstOrDefaultAsync(ct); + MeshNode? userNode = null; + for (var i = 0; i < 20 && userNode == null; i++) + { + userNode = await MeshQuery.QueryAsync($"path:{userMsgPath}") + .FirstOrDefaultAsync(ct); + if (userNode == null) await Task.Delay(200, ct); + } userNode.Should().NotBeNull("user message node must exist in persistence"); var userContent = userNode!.Content.Should().BeOfType().Subject; userContent.Role.Should().Be("user"); @@ -128,8 +156,13 @@ public async Task ExecuteThread_PersistsToCorrectPartition() Output.WriteLine($"User message OK: '{userContent.Text}'"); var responseMsgPath = $"{threadPath}/{msgIds[1]}"; - var responseNode = await MeshQuery.QueryAsync($"path:{responseMsgPath}") - .FirstOrDefaultAsync(ct); + MeshNode? responseNode = null; + for (var i = 0; i < 20 && responseNode == null; i++) + { + responseNode = await MeshQuery.QueryAsync($"path:{responseMsgPath}") + .FirstOrDefaultAsync(ct); + if (responseNode == null) await Task.Delay(200, ct); + } responseNode.Should().NotBeNull("response message node must exist in persistence"); responseNode!.NodeType.Should().Be(ThreadMessageNodeType.NodeType); Output.WriteLine($"Response message node exists in persistence: {responseNode.Path}"); @@ -153,12 +186,7 @@ public async Task ExecuteThread_ChildMessagesQueryableByNamespace() var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); - client.Post(new SubmitMessageRequest - { - ThreadPath = threadPath, - UserMessageText = "Test query by namespace", - ContextPath = ContextPath - }, o => o.WithTarget(new Address(threadPath))); + await CreateCellsAndSubmitAsync(client, threadPath, "Test query by namespace", ContextPath, ct); await twoMessages; @@ -194,13 +222,30 @@ public async Task ExecuteThread_SubmitMessageDoesNotTimeout() await CreateContextNodeAsync(ContextPath, ct); var threadPath = await CreateThreadAsync(client, ContextPath, "Timeout test", ct); - // Use AwaitResponse — if routing is broken, this will timeout + // Create cells and submit — if routing is broken, this will timeout + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Test no timeout", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var response = await client.AwaitResponse( new SubmitMessageRequest { ThreadPath = threadPath, UserMessageText = "Test no timeout", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); @@ -223,12 +268,7 @@ public async Task ExecuteThread_ThreadContentPersisted() var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); - client.Post(new SubmitMessageRequest - { - ThreadPath = threadPath, - UserMessageText = "Check persistence", - ContextPath = ContextPath - }, o => o.WithTarget(new Address(threadPath))); + await CreateCellsAndSubmitAsync(client, threadPath, "Check persistence", ContextPath, ct); var msgIds = await twoMessages; diff --git a/test/MeshWeaver.Threading.Test/ThreadResumeTest.cs b/test/MeshWeaver.Threading.Test/ThreadResumeTest.cs index f708e0ad8..64c093515 100644 --- a/test/MeshWeaver.Threading.Test/ThreadResumeTest.cs +++ b/test/MeshWeaver.Threading.Test/ThreadResumeTest.cs @@ -68,6 +68,31 @@ private static ImmutableList GetMessages(IEnumerable nodes, st return (node?.Content as MeshThread)?.Messages ?? ImmutableList.Empty; } + private async Task CreateCellsAndSubmitAsync( + IMessageHub client, string threadPath, string text, CancellationToken ct) + { + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = text, Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = text, ContextPath = ContextPath, + UserMessageId = userMsgId, ResponseMessageId = responseMsgId + }, o => o.WithTarget(new Address(threadPath)), ct); + } + private async Task WaitForMessageCompleteAsync(string messagePath, CancellationToken ct) { // Derive thread path from message path (parent directory) @@ -92,6 +117,21 @@ public async Task Resume_ThreadWithMessages_LoadsAllMessages() var threadPath = await CreateThreadAsync(client, "Resume test thread", ct); Output.WriteLine($"Thread: {threadPath}"); + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "First message for resume test", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var twoMessages = client.GetWorkspace() .GetRemoteStream(new Address(threadPath))! .Select(nodes => GetMessages(nodes, threadPath)) @@ -102,7 +142,9 @@ public async Task Resume_ThreadWithMessages_LoadsAllMessages() { ThreadPath = threadPath, UserMessageText = "First message for resume test", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); @@ -160,6 +202,21 @@ public async Task Resume_ThreadWithMultipleExchanges_LoadsAll() var threadPath = await CreateThreadAsync(client, "Multi-exchange resume test", ct); // Submit first message + var userMsgId1 = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId1 = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId1, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "First question", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId1, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var twoMessages = client.GetWorkspace() .GetRemoteStream(new Address(threadPath))! .Select(nodes => GetMessages(nodes, threadPath)) @@ -170,7 +227,9 @@ await client.AwaitResponse( { ThreadPath = threadPath, UserMessageText = "First question", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = userMsgId1, + ResponseMessageId = responseMsgId1 }, o => o.WithTarget(new Address(threadPath)), ct); @@ -178,6 +237,21 @@ await client.AwaitResponse( await WaitForMessageCompleteAsync($"{threadPath}/{firstMsgIds[1]}", ct); // Submit second message + var userMsgId2 = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId2 = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId2, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Second question", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId2, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + var fourMessages = client.GetWorkspace() .GetRemoteStream(new Address(threadPath))! .Select(nodes => GetMessages(nodes, threadPath)) @@ -188,7 +262,9 @@ await client.AwaitResponse( { ThreadPath = threadPath, UserMessageText = "Second question", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = userMsgId2, + ResponseMessageId = responseMsgId2 }, o => o.WithTarget(new Address(threadPath)), ct); diff --git a/test/MeshWeaver.Threading.Test/ThreadTestHelper.cs b/test/MeshWeaver.Threading.Test/ThreadTestHelper.cs new file mode 100644 index 000000000..84b6d0e8e --- /dev/null +++ b/test/MeshWeaver.Threading.Test/ThreadTestHelper.cs @@ -0,0 +1,103 @@ +using System; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using MeshWeaver.AI; +using MeshWeaver.Data; +using MeshWeaver.Mesh; +using MeshWeaver.Messaging; +using MeshThread = MeshWeaver.AI.Thread; + +namespace MeshWeaver.Threading.Test; + +/// +/// Shared helper for thread tests. Implements the portal flow: +/// create cells (verified) → submit → wait for execution. +/// +public static class ThreadTestHelper +{ + /// + /// Creates user + response cells, submits message, waits for execution to complete. + /// Returns the response text. + /// + public static async Task SubmitAndWaitAsync( + IMessageHub client, string threadPath, string text, + string contextPath, int expectedMsgCount, CancellationToken ct) + { + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + // Create user cell → verify + var userResp = await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = contextPath, + Content = new ThreadMessage + { + Role = "user", Text = text, Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.ExecutedInput + } + }), o => o.WithTarget(new Address(threadPath)), ct); + if (!userResp.Message.Success) + throw new InvalidOperationException($"User cell creation failed: {userResp.Message.Error}"); + + // Create response cell → verify + var responseResp = await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = contextPath, + Content = new ThreadMessage + { + Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, + Type = ThreadMessageType.AgentResponse + } + }), o => o.WithTarget(new Address(threadPath)), ct); + if (!responseResp.Message.Success) + throw new InvalidOperationException($"Response cell creation failed: {responseResp.Message.Error}"); + + // Submit (state update — WatchForExecution triggers execution) + await client.AwaitResponse(new SubmitMessageRequest + { + ThreadPath = threadPath, UserMessageText = text, ContextPath = contextPath, + UserMessageId = userMsgId, ResponseMessageId = responseMsgId + }, o => o.WithTarget(new Address(threadPath)), ct); + + // Wait for execution to complete + return await WaitForExecutionAsync(client, threadPath, responseMsgId, expectedMsgCount, ct); + } + + /// + /// Polls until IsExecuting=false and Messages.Count >= expectedMsgCount. + /// Returns the last response message text. + /// + public static async Task WaitForExecutionAsync( + IMessageHub client, string threadPath, string responseMsgId, + int expectedMsgCount, CancellationToken ct) + { + for (var i = 0; i < 60; i++) + { + var threadNodeId = threadPath.Contains('/') ? threadPath[(threadPath.LastIndexOf('/') + 1)..] : threadPath; + var dataResp = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), threadNodeId)), + o => o.WithTarget(new Address(threadPath)), ct); + var node = dataResp.Message.Data as MeshNode; + var thread = node?.Content as MeshThread; + if (thread == null && node?.Content is JsonElement je) + thread = je.Deserialize(client.JsonSerializerOptions); + + if (thread is { IsExecuting: false } && thread.Messages.Count >= expectedMsgCount) + { + var msgId = responseMsgId ?? thread.Messages[^1]; + var msgResp = await client.AwaitResponse( + new GetDataRequest(new EntityReference(nameof(MeshNode), msgId)), + o => o.WithTarget(new Address($"{threadPath}/{msgId}")), ct); + var msgNode = msgResp.Message.Data as MeshNode; + var tmsg = msgNode?.Content as ThreadMessage; + if (tmsg == null && msgNode?.Content is JsonElement mje) + tmsg = mje.Deserialize(client.JsonSerializerOptions); + if (tmsg?.Text is { Length: > 0 }) + return tmsg.Text; + } + await Task.Delay(200, ct); + } + throw new TimeoutException($"Execution did not complete for {threadPath}"); + } +} diff --git a/test/MeshWeaver.Threading.Test/ToolCallingTest.cs b/test/MeshWeaver.Threading.Test/ToolCallingTest.cs index bd9879920..565cebda6 100644 --- a/test/MeshWeaver.Threading.Test/ToolCallingTest.cs +++ b/test/MeshWeaver.Threading.Test/ToolCallingTest.cs @@ -110,11 +110,27 @@ await NodeFactory.CreateNodeAsync(new MeshNode("test-doc", ContextPath) var threadPath = await CreateThreadAsync(client, "Tool calling test", ct); Output.WriteLine($"Thread created: {threadPath}"); - // 3. Subscribe to Messages + // 3. Create cells before submitting (GUI flow) + var userMsgId = Guid.NewGuid().ToString("N")[..8]; + var responseMsgId = Guid.NewGuid().ToString("N")[..8]; + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(userMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "user", Text = "Search for test documents", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.ExecutedInput } + }), o => o.WithTarget(new Address(threadPath)), ct); + + await client.AwaitResponse(new CreateNodeRequest(new MeshNode(responseMsgId, threadPath) + { + NodeType = ThreadMessageNodeType.NodeType, MainNode = ContextPath, + Content = new ThreadMessage { Role = "assistant", Text = "", Timestamp = DateTime.UtcNow, Type = ThreadMessageType.AgentResponse } + }), o => o.WithTarget(new Address(threadPath)), ct); + + // 4. Subscribe to Messages var twoMessages = ObserveMessages(client, threadPath) .Where(ids => ids.Count >= 2).FirstAsync().ToTask(ct); - // 4. Submit message — the ToolCallingFakeChatClient will: + // 5. Submit message — the ToolCallingFakeChatClient will: // a) Return a Search tool call on first invocation // b) The ChatClientAgent framework will execute the Search tool // c) On second invocation (with tool result), return a text response @@ -123,7 +139,9 @@ await NodeFactory.CreateNodeAsync(new MeshNode("test-doc", ContextPath) { ThreadPath = threadPath, UserMessageText = "Search for test documents", - ContextPath = ContextPath + ContextPath = ContextPath, + UserMessageId = userMsgId, + ResponseMessageId = responseMsgId }, o => o.WithTarget(new Address(threadPath)), ct); submitResponse.Message.Success.Should().BeTrue(submitResponse.Message.Error); diff --git a/test/MeshWeaver.Threading.Test/ToolCallsVisibilityTest.cs b/test/MeshWeaver.Threading.Test/ToolCallsVisibilityTest.cs index 5db625493..ee38caf3a 100644 --- a/test/MeshWeaver.Threading.Test/ToolCallsVisibilityTest.cs +++ b/test/MeshWeaver.Threading.Test/ToolCallsVisibilityTest.cs @@ -72,7 +72,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) MainNode = "User/Roland", Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "Working on it...", Type = ThreadMessageType.AgentResponse, @@ -134,7 +133,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) MainNode = "User/Roland", Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "", Type = ThreadMessageType.AgentResponse, @@ -186,7 +184,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode("toolcalls-update-test", "User/Ro { Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "", Type = ThreadMessageType.AgentResponse, @@ -237,7 +234,7 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) MainNode = "User/Roland", Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "", + Role = "assistant", Text = "", Type = ThreadMessageType.AgentResponse, AgentName = "Orchestrator" } }, ct); @@ -278,7 +275,7 @@ await NodeFactory.CreateNodeAsync(new MeshNode("toolcalls-lifecycle-test", "User { Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "", + Role = "assistant", Text = "", Type = ThreadMessageType.AgentResponse, AgentName = "Orchestrator", ToolCalls = ImmutableList.Create(new ToolCallEntry { @@ -340,7 +337,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode(responseMsgId, threadPath) MainNode = "User/Roland", Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "", Type = ThreadMessageType.AgentResponse, @@ -394,7 +390,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode("feedback-loop-test", "User/Rolan { Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "", Type = ThreadMessageType.AgentResponse, @@ -436,7 +431,6 @@ await NodeFactory.CreateNodeAsync(new MeshNode("feedback-loop-test", "User/Rolan { Content = new ThreadMessage { - Id = responseMsgId, Role = "assistant", Text = "Done.", Type = ThreadMessageType.AgentResponse, diff --git a/test/MeshWeaver.Threading.Test/appsettings.json b/test/MeshWeaver.Threading.Test/appsettings.json new file mode 100644 index 000000000..a634d4e8c --- /dev/null +++ b/test/MeshWeaver.Threading.Test/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning", + "MeshWeaver.AI.AgentChatClient": "Debug" + } + } +} diff --git a/tools/MeshWeaver.Tools.CosmosImport/MeshWeaver.Tools.CosmosImport.csproj b/tools/MeshWeaver.Tools.CosmosImport/MeshWeaver.Tools.CosmosImport.csproj index f4749388e..8f614c07c 100644 --- a/tools/MeshWeaver.Tools.CosmosImport/MeshWeaver.Tools.CosmosImport.csproj +++ b/tools/MeshWeaver.Tools.CosmosImport/MeshWeaver.Tools.CosmosImport.csproj @@ -1,6 +1,7 @@ Exe + false diff --git a/tools/MeshWeaver.Tools.PostgreSqlImport/MeshWeaver.Tools.PostgreSqlImport.csproj b/tools/MeshWeaver.Tools.PostgreSqlImport/MeshWeaver.Tools.PostgreSqlImport.csproj index e1a8f6dcc..9e81288a5 100644 --- a/tools/MeshWeaver.Tools.PostgreSqlImport/MeshWeaver.Tools.PostgreSqlImport.csproj +++ b/tools/MeshWeaver.Tools.PostgreSqlImport/MeshWeaver.Tools.PostgreSqlImport.csproj @@ -1,6 +1,7 @@ Exe + false From eeb9854638306e7558411143c823c57da4e0f5d4 Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Sun, 12 Apr 2026 20:23:23 +0200 Subject: [PATCH 08/14] aspire-deployment-changes Bring FutuRe aspire state to deployment-test: optional secrets with null-check defaults, AzureAIS model endpoints, simplified mode handling, migration v6 rewrite (permissions rebuild), logging config cleanup, and updated deployment docs. Co-Authored-By: Claude Opus 4.6 --- memex/aspire/Memex.AppHost/Program.cs | 121 ++++---- .../Memex.Database.Migration/Program.cs | 189 ++++++------- .../appsettings.Development.json | 4 +- .../Memex.Portal.Distributed/appsettings.json | 4 +- .../Data/Architecture/Deployment.md | 262 ++++-------------- 5 files changed, 198 insertions(+), 382 deletions(-) diff --git a/memex/aspire/Memex.AppHost/Program.cs b/memex/aspire/Memex.AppHost/Program.cs index 8a8ee9f45..fb49370a3 100644 --- a/memex/aspire/Memex.AppHost/Program.cs +++ b/memex/aspire/Memex.AppHost/Program.cs @@ -20,20 +20,14 @@ // // Required user-secrets for distributed modes: // Parameters:azure-foundry-key +// Parameters:embedding-endpoint +// Parameters:embedding-key +// Parameters:embedding-model // Parameters:microsoft-client-id // Parameters:microsoft-client-secret -// -// Optional user-secrets (features disabled when absent): -// Parameters:embedding-endpoint, embedding-key, embedding-model -// Parameters:google-client-id, google-client-secret -// Parameters:custom-domain, certificate-name -// -// For local-test/local-prod, also set the connection string to the Azure PostgreSQL: -// ConnectionStrings:memex (Azure PostgreSQL, bypassing provisioning) -// Blob Storage uses RunAsExisting with Azure Identity (az login) — no secrets needed. +// Parameters:microsoft-tenant-id -var mode = builder.Configuration["mode"]?.ToLowerInvariant() - ?? (builder.ExecutionContext.IsPublishMode ? "test" : "local"); +var mode = builder.Configuration["mode"]?.ToLowerInvariant() ?? "local"; if (mode == "monolith") { @@ -51,29 +45,27 @@ // LLM API key (single Azure Foundry key for both Anthropic and OpenAI endpoints) var azureFoundryKey = builder.AddParameter("azure-foundry-key", secret: true); -// Embedding — optional: skip if embedding-key is not configured -var hasEmbedding = !string.IsNullOrEmpty(builder.Configuration["Parameters:embedding-key"]); -var embeddingEndpoint = hasEmbedding ? builder.AddParameter("embedding-endpoint", secret: false) : null; -var embeddingKey = hasEmbedding ? builder.AddParameter("embedding-key", secret: true) : null; -var embeddingModel = hasEmbedding ? builder.AddParameter("embedding-model", secret: false) : null; - -// Authentication — Microsoft (required) +// Authentication (Microsoft is required; Google is optional for local) var microsoftClientId = builder.AddParameter("microsoft-client-id", secret: false); var microsoftClientSecret = builder.AddParameter("microsoft-client-secret", secret: true); - -// Authentication — Microsoft tenant (optional: defaults to "common" for multi-tenant) -var hasTenantId = !string.IsNullOrEmpty(builder.Configuration["Parameters:microsoft-tenant-id"]); -var microsoftTenantId = hasTenantId ? builder.AddParameter("microsoft-tenant-id", secret: false) : null; - -// Authentication — Google (optional: skip if google-client-secret is not configured) -var hasGoogleAuth = !string.IsNullOrEmpty(builder.Configuration["Parameters:google-client-secret"]); -var googleClientId = hasGoogleAuth ? builder.AddParameter("google-client-id", secret: false) : null; -var googleClientSecret = hasGoogleAuth ? builder.AddParameter("google-client-secret", secret: true) : null; - -// --- Custom domain (optional, for deployed modes with DNS configured) --- -var hasCustomDomain = !string.IsNullOrEmpty(builder.Configuration["Parameters:custom-domain"]); -var customDomain = hasCustomDomain ? builder.AddParameter("custom-domain", secret: false) : null; -var certificateName = hasCustomDomain ? builder.AddParameter("certificate-name", secret: false) : null; +var microsoftTenantId = builder.AddParameter("microsoft-tenant-id", secret: false); + +// Embedding, Google auth, and custom domain (non-secret optional — ACA accepts empty env vars) +var embeddingEndpoint = builder.AddParameter("embedding-endpoint", value: "", secret: false); +var embeddingModel = builder.AddParameter("embedding-model", value: "", secret: false); +var googleClientId = builder.AddParameter("google-client-id", value: "", secret: false); +var customDomain = builder.AddParameter("custom-domain", value: "", secret: false); +var certificateName = builder.AddParameter("certificate-name", value: "", secret: false); + +// Optional secrets/params: ACA rejects secrets with empty values; ConfigureCustomDomain +// rejects empty hostnames. Read actual config values to guard optional registrations. +var embeddingKeyValue = builder.Configuration["Parameters:embedding-key"] ?? ""; +var googleClientSecretValue = builder.Configuration["Parameters:google-client-secret"] ?? ""; +var customDomainValue = builder.Configuration["Parameters:custom-domain"] ?? ""; +IResourceBuilder? embeddingKey = string.IsNullOrEmpty(embeddingKeyValue) + ? null : builder.AddParameter("embedding-key", secret: true); +IResourceBuilder? googleClientSecret = string.IsNullOrEmpty(googleClientSecretValue) + ? null : builder.AddParameter("google-client-secret", secret: true); // --- Infrastructure axes --- var isDeployed = mode is "test" or "prod"; @@ -126,12 +118,9 @@ // --- Database Migration --- var dbMigration = builder .AddProject("db-migration") - .WithEnvironment("Embedding__Model", embeddingModel); - -if (!useLocalDb) -{ - dbMigration.WithReference(appInsights).WaitFor(appInsights); -} + .WithEnvironment("Embedding__Model", embeddingModel) + .WithReference(appInsights) + .WaitFor(appInsights); // --- Portal (co-hosted Orleans silo + web) --- var portal = builder @@ -139,6 +128,11 @@ .WithExternalHttpEndpoints() .WithReference(orleans) .WithReference(appInsights) + // Local modes need Development environment for static web assets (_framework, _content) + .WithEnvironment("ASPNETCORE_ENVIRONMENT", isDeployed ? "Production" : "Development") + // Embedding + .WithEnvironment("Embedding__Endpoint", embeddingEndpoint) + .WithEnvironment("Embedding__Model", embeddingModel) // LLM: Anthropic (Azure Foundry Claude) .WithEnvironment("Anthropic__Endpoint", "https://s-meshweaver.services.ai.azure.com/anthropic/") .WithEnvironment("Anthropic__ApiKey", azureFoundryKey) @@ -154,26 +148,29 @@ .WithEnvironment("AzureOpenAIS__ApiKey", azureFoundryKey) .WithEnvironment("AzureOpenAIS__Models__0", "gpt-5-mini") .WithEnvironment("AzureOpenAIS__Models__1", "gpt-5.4") - // Authentication — Microsoft (required) + // LLM: Azure AI Foundry (multi-model inference endpoint) + .WithEnvironment("AzureAIS__Endpoint", "https://fy-meshweaver3-dev-swc-001.services.ai.azure.com/models") + .WithEnvironment("AzureAIS__ApiKey", azureFoundryKey) + .WithEnvironment("AzureAIS__Models__0", "gpt-5.4") + .WithEnvironment("AzureAIS__Models__1", "gpt-5.3-codex") + .WithEnvironment("AzureAIS__Models__2", "Mistral-Large-3") + .WithEnvironment("AzureAIS__Models__3", "DeepSeek-V3.2") + .WithEnvironment("AzureAIS__Order", "1") + // Authentication .WithEnvironment("Authentication__EnableDevLogin", mode != "prod" ? "true" : "false") .WithEnvironment("Authentication__Microsoft__ClientId", microsoftClientId) .WithEnvironment("Authentication__Microsoft__ClientSecret", microsoftClientSecret) - .WithEnvironment("Authentication__Microsoft__TenantId", "common") + .WithEnvironment("Authentication__Microsoft__TenantId", microsoftTenantId) + .WithEnvironment("Authentication__Google__ClientId", googleClientId) // Wait for dependencies .WaitFor(orleansTables) .WaitForCompletion(dbMigration) // ACA deployment: sticky sessions (Blazor Server) + custom domain + resources .PublishAsAzureContainerApp((module, app) => { - // Fix: Aspire's Orleans integration sets primary ingress to TCP/internal - // on the silo port. Override to HTTP/external for the Blazor web app. - app.Configuration.Ingress.External = true; - app.Configuration.Ingress.Transport = ContainerAppIngressTransportMethod.Auto; - app.Configuration.Ingress.TargetPort = 8080; - app.Configuration.Ingress.StickySessionsAffinity = StickySessionAffinity.Sticky; - if (hasCustomDomain) - app.ConfigureCustomDomain(customDomain!, certificateName!); + if (!string.IsNullOrEmpty(customDomainValue)) + app.ConfigureCustomDomain(customDomain, certificateName); // Scale: min 2 replicas (Orleans needs ≥2 for resilience), max 6 under load. // Each replica: 2 vCPU / 4Gi (50% of Consumption tier max 4 vCPU / 8Gi). @@ -181,29 +178,11 @@ app.Template.Scale.MaxReplicas = 6; }); -// Embedding — optional -if (hasEmbedding) -{ - portal = portal - .WithEnvironment("Embedding__Endpoint", embeddingEndpoint!) - .WithEnvironment("Embedding__ApiKey", embeddingKey!) - .WithEnvironment("Embedding__Model", embeddingModel!); -} - -// Authentication — Google (optional) -if (hasGoogleAuth) -{ - portal = portal - .WithEnvironment("Authentication__Google__ClientId", googleClientId!) - .WithEnvironment("Authentication__Google__ClientSecret", googleClientSecret!); -} - -// Authentication — Microsoft tenant (optional: overrides "common" default) -if (hasTenantId) -{ - portal = portal - .WithEnvironment("Authentication__Microsoft__TenantId", microsoftTenantId!); -} +// Optional secrets: only add as env vars when configured (ACA rejects empty secrets) +if (embeddingKey is not null) + portal.WithEnvironment("Embedding__ApiKey", embeddingKey); +if (googleClientSecret is not null) + portal.WithEnvironment("Authentication__Google__ClientSecret", googleClientSecret); // --- Azure Blob Storage --- if (useLocalDb) diff --git a/memex/aspire/Memex.Database.Migration/Program.cs b/memex/aspire/Memex.Database.Migration/Program.cs index a8dc4d7ea..aa0fbe18e 100644 --- a/memex/aspire/Memex.Database.Migration/Program.cs +++ b/memex/aspire/Memex.Database.Migration/Program.cs @@ -36,12 +36,11 @@ // (portal, migration) can create per-organization schemas at runtime. if (connectionString.Contains("database.azure.com")) { - var csb = new NpgsqlConnectionStringBuilder(connectionString); - var dbName = csb.Database ?? "memex"; + var dbName = new NpgsqlConnectionStringBuilder(connectionString).Database ?? "memex"; await using var grantCmd = dataSource.CreateCommand( $"GRANT CREATE ON DATABASE \"{dbName}\" TO azure_pg_admin"); await grantCmd.ExecuteNonQueryAsync(); - logger.LogInformation("Granted CREATE ON DATABASE {Database} to azure_pg_admin.", dbName); + logger.LogInformation("Granted CREATE ON DATABASE to azure_pg_admin."); } // ═══════════════════════════════════════════════════════════════════════════ @@ -429,65 +428,104 @@ EXCEPTION WHEN OTHERS THEN logger.LogInformation("Repair v5 completed."); } -// ── Data repair v6: Fix search_across_schemas to enforce partition_access ── -// Bug: public_read node types bypassed partition_access entirely, leaking -// cross-partition data in search (e.g., meshweaver user could see PartnerRe). -// Fix: partition_access is now always required; public_read only skips -// node-level permission checks within accessible partitions. -// The stored proc is re-created by InitializePublicSchemaAsync (idempotent). +// ── Data repair v6: Rebuild user_effective_permissions for all schemas ── +// Ensures self-assignments and permissions are correct after fresh deployments, +// schema re-initialization, or any silent failure in UserScopeGrantHandler. +// This runs on fresh DBs (currentVersion=5 is set, not 6) and existing DBs alike. if (currentVersion < 6) { - logger.LogInformation("Running repair v6: Fix search_across_schemas access control..."); - // Re-create the stored procedure with fixed access control logic - await PostgreSqlSchemaInitializer.InitializePartitionAccessTableAsync(dataSource); - currentVersion = 6; - logger.LogInformation("Repair v6 completed — search_across_schemas updated."); -} - -// ── Data repair v7: Deploy per-user permission rebuild trigger ── -// The trigger function trg_access_changed() previously called rebuild_user_effective_permissions() -// which rebuilds ALL users' permissions — causing deadlocks under concurrent access. -// New trigger calls rebuild_user_permissions_for(affected_user) — only touches one user's rows. -// The schema initializer already creates the new functions; we just need to re-run schema init -// per partition to deploy the updated trigger function. -if (currentVersion < 7) -{ - logger.LogInformation("Running repair v7: Deploy per-user permission rebuild trigger..."); + logger.LogInformation("Running repair v6: Ensure user self-assignments and rebuild all permissions..."); + await using (var cmd = dataSource.CreateCommand(""" + DO $$ + DECLARE + user_rec RECORD; + schema_rec RECORD; + assignment_exists BOOLEAN; + user_schema_exists BOOLEAN; + BEGIN + -- Guard: user schema may not exist on fresh DBs + SELECT EXISTS( + SELECT 1 FROM information_schema.schemata + WHERE schema_name = 'user' + ) INTO user_schema_exists; + + IF user_schema_exists THEN + -- Ensure every User node has an Admin self-assignment + FOR user_rec IN + SELECT id FROM "user".mesh_nodes WHERE node_type = 'User' + LOOP + SELECT EXISTS( + SELECT 1 FROM "user".access + WHERE namespace = 'User/' || user_rec.id || '/_Access' + AND content->>'accessObject' = user_rec.id + ) INTO assignment_exists; + + IF NOT assignment_exists THEN + INSERT INTO "user".access (id, namespace, name, node_type, content, main_node, last_modified, version, state) + VALUES ( + user_rec.id || '_SelfAccess', + 'User/' || user_rec.id || '/_Access', + user_rec.id || ' Self Access', + 'AccessAssignment', + jsonb_build_object( + 'accessObject', user_rec.id, + 'displayName', user_rec.id, + 'roles', jsonb_build_array(jsonb_build_object('role', 'Admin')) + ), + 'User/' || user_rec.id, + NOW(), 1, 2 + ); + RAISE NOTICE 'v6: Created self-assignment for user %', user_rec.id; + END IF; + END LOOP; + + -- Rebuild permissions for user schema + BEGIN + PERFORM "user".rebuild_user_effective_permissions(); + RAISE NOTICE 'v6: Rebuilt permissions for user schema'; + EXCEPTION WHEN OTHERS THEN + RAISE NOTICE 'v6: user schema rebuild failed: %', SQLERRM; + END; + ELSE + RAISE NOTICE 'v6: user schema does not exist yet — skipping (trigger will handle first login)'; + END IF; - var schemas = new List(); - await using (var listCmd = dataSource.CreateCommand(""" - SELECT schema_name FROM information_schema.schemata s - WHERE EXISTS (SELECT 1 FROM information_schema.tables t WHERE t.table_schema = s.schema_name AND t.table_name = 'access') - AND s.schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast') - AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' - ORDER BY s.schema_name + -- Rebuild permissions for all other content schemas + FOR schema_rec IN + SELECT schema_name FROM information_schema.schemata s + WHERE EXISTS (SELECT 1 FROM information_schema.tables t + WHERE t.table_schema = s.schema_name AND t.table_name = 'access') + AND s.schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast', 'user') + AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' + LOOP + BEGIN + EXECUTE format('SELECT %I.rebuild_user_effective_permissions()', schema_rec.schema_name); + RAISE NOTICE 'v6: Rebuilt permissions for schema %', schema_rec.schema_name; + EXCEPTION WHEN OTHERS THEN + RAISE NOTICE 'v6: Schema % rebuild failed: %', schema_rec.schema_name, SQLERRM; + END; + END LOOP; + END $$; """)) { - await using var rdr = await listCmd.ExecuteReaderAsync(); - while (await rdr.ReadAsync()) schemas.Add(rdr.GetString(0)); + await cmd.ExecuteNonQueryAsync(); } - foreach (var schema in schemas) - { - logger.LogInformation("Repair v7: Updating trigger functions for schema {Schema}...", schema); - var csb = new NpgsqlConnectionStringBuilder(connectionString) { SearchPath = $"{schema},public" }; - var dsb = new NpgsqlDataSourceBuilder(csb.ConnectionString); - dsb.UseVector(); - await using var schemaDs = dsb.Build(); - - var schemaOpts = new PostgreSqlStorageOptions - { - ConnectionString = csb.ConnectionString, - VectorDimensions = options.Value.VectorDimensions, - Schema = schema - }; - - await PostgreSqlSchemaInitializer.InitializeMeshTablesAsync(schemaDs, schemaOpts); - logger.LogInformation("Repair v7: Schema {Schema} — trigger updated", schema); - } + currentVersion = 6; + logger.LogInformation("Repair v6 completed."); +} - currentVersion = 7; - logger.LogInformation("Repair v7 completed."); +// ── Always: rebuild user_effective_permissions to catch any new logins since last deploy ── +try +{ + await using var rebuildCmd = dataSource.CreateCommand( + "SELECT \"user\".rebuild_user_effective_permissions()"); + await rebuildCmd.ExecuteNonQueryAsync(); + logger.LogInformation("Rebuilt user_effective_permissions for user schema."); +} +catch (Exception ex) +{ + logger.LogWarning(ex, "Could not rebuild user_effective_permissions (user schema may not exist yet)."); } // ── Always: populate searchable_schemas from remaining content partitions ── @@ -536,49 +574,6 @@ ORDER BY s.schema_name logger.LogInformation("Searchable schemas: [{Schemas}]", string.Join(", ", contentSchemas)); } -// ── Data repair v8: Fix ThreadMessage MainNode ── -// Thread message nodes created from the UI may have MainNode set to the thread path -// (e.g., "Org/_Thread/thread-id") instead of the thread's content node (e.g., "Org"). -// This causes "Access denied" because SatelliteAccessRule delegates to MainNode. -// Fix: set MainNode = the part before "/_Thread/" for all ThreadMessage nodes. -if (currentVersion < 8) -{ - logger.LogInformation("Running repair v8: Fix ThreadMessage MainNode..."); - var totalFixed = 0; - - var schemas = new List(); - await using (var listCmd = dataSource.CreateCommand(""" - SELECT schema_name FROM information_schema.schemata s - WHERE EXISTS (SELECT 1 FROM information_schema.tables t WHERE t.table_schema = s.schema_name AND t.table_name = 'mesh_nodes') - AND s.schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast', 'admin') - AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' - ORDER BY s.schema_name - """)) - { - await using var rdr = await listCmd.ExecuteReaderAsync(); - while (await rdr.ReadAsync()) schemas.Add(rdr.GetString(0)); - } - - foreach (var schema in schemas) - { - await using var fixCmd = dataSource.CreateCommand($""" - UPDATE "{schema}".mesh_nodes - SET main_node = split_part(main_node, '/_Thread/', 1) - WHERE node_type = 'ThreadMessage' - AND main_node LIKE '%/_Thread/%' - """); - var affected = await fixCmd.ExecuteNonQueryAsync(); - if (affected > 0) - { - logger.LogInformation("Repair v8: Fixed {Count} ThreadMessage MainNode(s) in schema {Schema}", affected, schema); - totalFixed += affected; - } - } - - currentVersion = 8; - logger.LogInformation("Repair v8 completed — fixed {Total} ThreadMessage MainNode(s)", totalFixed); -} - // Save current version await using (var saveVersion = dataSource.CreateCommand(""" INSERT INTO admin.mesh_nodes (namespace, id, name, node_type, state, content, last_modified, main_node) diff --git a/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json b/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json index 6e539eb49..ce0ba8495 100644 --- a/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json +++ b/memex/aspire/Memex.Portal.Distributed/appsettings.Development.json @@ -5,9 +5,7 @@ "Default": "Warning", "Microsoft.AspNetCore": "Warning", "MeshWeaver": "Warning", - "MeshWeaver.AI": "Information", - "MeshWeaver.Layout.ConvertJson": "Warning", - "MeshWeaver.Messaging.Hub.MessageHub": "Warning", + "MeshWeaver.AI": "Warning", "Azure.Core": "Warning", "Orleans": "Warning", "Memex": "Warning", diff --git a/memex/aspire/Memex.Portal.Distributed/appsettings.json b/memex/aspire/Memex.Portal.Distributed/appsettings.json index 71029baf8..eba7ad520 100644 --- a/memex/aspire/Memex.Portal.Distributed/appsettings.json +++ b/memex/aspire/Memex.Portal.Distributed/appsettings.json @@ -1,9 +1,7 @@ { "Logging": { "LogLevel": { - "Default": "Warning", - "MeshWeaver.AI": "Information", - "MeshWeaver.Hosting.Orleans.RoutingGrain": "Information" + "Default": "Warning" } }, "AllowedHosts": "*", diff --git a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md index 9c64b8a2c..efe0a5b05 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md @@ -7,71 +7,6 @@ Icon: Cloud MeshWeaver uses **.NET Aspire** for orchestration and deployment. The Aspire AppHost (`memex/aspire/Memex.AppHost`) defines all infrastructure resources — PostgreSQL, Azure Blob Storage, Orleans clustering, Application Insights — and provisions them automatically via the Aspire CLI. -# Prerequisites - -## Aspire CLI - -Install the Aspire CLI as a global .NET tool: - -```bash -dotnet tool install -g aspire.cli -``` - -Verify installation: - -```bash -aspire --version -``` - -## Azure Login - -You must be logged into Azure before deploying: - -```bash -az login -azd auth login -``` - -## User Secrets - -All parameters must be configured via `dotnet user-secrets` before deploying. Without secrets, `aspire deploy` will prompt interactively for each missing parameter and fail in non-interactive environments (CI/CD, piped shells). - -Set secrets from the AppHost project directory: - -```bash -cd memex/aspire/Memex.AppHost -dotnet user-secrets set "Parameters:azure-foundry-key" "" -dotnet user-secrets set "Parameters:microsoft-client-id" "" -dotnet user-secrets set "Parameters:microsoft-client-secret" "" -``` - -Or from the repository root using `--project`: - -```bash -dotnet user-secrets set "Parameters:azure-foundry-key" "" --project memex/aspire/Memex.AppHost -``` - -The three secrets above are **required** — deployment fails without them. The following are **optional** (features are disabled when absent — the AppHost skips these parameters automatically): - -```bash -dotnet user-secrets set "Parameters:microsoft-tenant-id" "" -dotnet user-secrets set "Parameters:embedding-endpoint" "" -dotnet user-secrets set "Parameters:embedding-key" "" -dotnet user-secrets set "Parameters:embedding-model" "" -dotnet user-secrets set "Parameters:google-client-id" "" -dotnet user-secrets set "Parameters:google-client-secret" "" -dotnet user-secrets set "Parameters:custom-domain" "" -dotnet user-secrets set "Parameters:certificate-name" "" -``` - -> **Important:** For `microsoft-client-secret`, use the secret **value** (the string shown once when you create the secret), not the secret **ID** (the GUID). These are different fields in the Azure portal. - -Verify secrets are configured: - -```bash -dotnet user-secrets list --project memex/aspire/Memex.AppHost -``` - # Deployment Modes The AppHost supports multiple modes, passed as `--mode `: @@ -85,68 +20,31 @@ The AppHost supports multiple modes, passed as `--mode `: | `prod` | Azure (memex) | Azure (meshweavermemex) | Azure | memex-prod | | `monolith` | FileSystem (standalone) | — | — | memex-monolith | -# Deploying to Azure +# Deploying to Production -All `aspire deploy` commands require `-e Development`. This tells Aspire to use the **ASP.NET Development environment**, which is what loads user secrets. Without it, Aspire defaults to the Production environment where user secrets are ignored, causing interactive prompts that fail in non-interactive terminals. The **deployment target** (test vs prod) is controlled separately by the `--mode` flag. - -## Deploy to Test +Deploy using the Aspire CLI: ```bash -aspire deploy -e Development --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode test +aspire deploy --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode prod ``` -## Deploy to Production +For test environment: ```bash -aspire deploy -e Development --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode prod +aspire deploy --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode test ``` -## What `aspire deploy` Does - -1. **Builds** the AppHost project and resolves the Aspire application model -2. **Prompts for parameters** — reads from user-secrets; prompts interactively for any missing values -3. **Generates Bicep** infrastructure templates (stored in `memex/aspire/Memex.AppHost/infra/`) -4. **Provisions Azure resources** via ARM deployment (resource group, Container App Environment, PostgreSQL, Blob Storage, etc.) -5. **Builds container images** for each project (portal, db-migration) -6. **Pushes images** to the provisioned Azure Container Registry -7. **Deploys Container Apps** with the configured environment variables, scaling rules, and custom domain - -## Generated Infrastructure - -The first `aspire deploy` generates Bicep templates in `memex/aspire/Memex.AppHost/infra/`: - -``` -infra/ -├── main.bicep # Root deployment template -├── main.parameters.json # Parameter bindings (uses ${AZURE_*} env vars) -├── memex-aca/ # Container App Environment -├── memex-aca-acr/ # Container Registry -├── memex-test/ or memex-prod/ # Portal Container App -├── db-migration/ # Migration Container App (run-to-completion) -├── memex-postgres/ # PostgreSQL Flexible Server -├── memexblobs/ # Azure Storage Account -├── orleansstorage/ # Orleans Storage Account -├── appinsights/ # Application Insights -└── *-identity/, *-roles-*/ # Managed identities and role assignments -``` - -These templates are committed to the repo and reused on subsequent deploys. To regenerate them: - -```bash -aspire generate --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode test -``` +The `aspire deploy` command builds the application, pushes container images, and provisions/updates Azure resources as defined in the AppHost. # Running Locally -## Local Development (Docker) +For local development with Docker containers: ```bash aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode local ``` -This starts in `local` mode by default, using Docker pgvector and emulated Azure services (Azurite). - -## Local with Azure Databases +This starts in `local` mode by default, using Docker pgvector and emulated Azure services. To run locally against Azure test or prod databases: @@ -155,9 +53,7 @@ aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode l aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode local-prod ``` -These modes connect to Azure PostgreSQL and Blob Storage while keeping Orleans emulated locally. Requires: -- `ConnectionStrings:memex` user secret (PostgreSQL connection string) -- Active `az login` session (for Blob Storage via Azure Identity) +These modes connect to Azure PostgreSQL and Blob Storage while keeping Orleans emulated locally. # Monolith Mode @@ -177,10 +73,7 @@ aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode m ## Azure Container Apps -Deployed modes (`test`, `prod`) run on **Azure Container Apps** in Sweden Central: -- **Sticky sessions** enabled for Blazor Server (session affinity) -- **Custom domain** with managed TLS certificate -- **Scaling**: 2–6 replicas (min 2 for Orleans resilience), 2 vCPU / 4Gi per replica +Deployed modes (`test`, `prod`) run on **Azure Container Apps** in Sweden Central with sticky sessions enabled for Blazor Server. ## PostgreSQL @@ -190,11 +83,10 @@ Deployed modes (`test`, `prod`) run on **Azure Container Apps** in Sweden Centra ## Azure Blob Storage -Content files (attachments, documents) and data protection keys are stored in Azure Blob Storage. +Content files (attachments, documents) are stored in Azure Blob Storage. -- **Local**: Azurite emulator with persistent data bind mount (`Azurite/Data/`) +- **Local**: Azurite emulator with persistent data bind mount - **Deployed**: Azure Storage Account provisioned in Sweden Central -- **local-test/local-prod**: Connects via Azure Identity (`az login`), no secrets needed ## Orleans @@ -205,107 +97,61 @@ Orleans provides distributed actor clustering for the microservices deployment. ## Application Insights -Telemetry and distributed tracing via Azure Application Insights, provisioned automatically in all modes. - -# Secrets Reference - -| Secret | Required | Description | -|--------|----------|-------------| -| `Parameters:azure-foundry-key` | **Yes** | Azure AI Foundry API key (LLM access) | -| `Parameters:microsoft-client-id` | **Yes** | Microsoft OAuth client ID | -| `Parameters:microsoft-client-secret` | **Yes** | Microsoft OAuth client secret (**value**, not ID) | -| `Parameters:embedding-endpoint` | No | Embedding model endpoint (embedding disabled when absent) | -| `Parameters:embedding-key` | No | Embedding model API key | -| `Parameters:embedding-model` | No | Embedding model name | -| `Parameters:microsoft-tenant-id` | No | Microsoft Entra tenant ID (defaults to `common` for multi-tenant) | -| `Parameters:google-client-id` | No | Google OAuth client ID (Google login disabled when absent) | -| `Parameters:google-client-secret` | No | Google OAuth client secret | -| `Parameters:custom-domain` | No | Custom domain for deployed portal | -| `Parameters:certificate-name` | No | TLS certificate name for custom domain | -| `ConnectionStrings:memex` | local-test/local-prod only | Azure PostgreSQL connection string | +Telemetry and distributed tracing via Azure Application Insights, provisioned automatically in all deployed modes. -# Project Structure +# Azure AD App Registration -``` -memex/aspire/ -├── Memex.AppHost/ # Aspire orchestrator (defines all resources) -│ ├── Program.cs # Mode matrix, resource definitions, parameters -│ ├── azure.yaml # Azure Developer CLI service definition -│ └── infra/ # Generated Bicep templates (committed) -├── Memex.Portal.Distributed/ # Portal with co-hosted Orleans silo -├── Memex.Portal.Orleans/ # Orleans grain interfaces -├── Memex.Portal.ServiceDefaults/# Shared service defaults (health, telemetry) -└── Memex.Database.Migration/ # Database migration project (run-to-completion) -``` +Microsoft authentication requires an app registration in Microsoft Entra ID (Azure AD): -# First-Time Deployment Checklist +1. **Azure Portal** → **App registrations** → select your app (or create one) +2. Under **Authentication** → **Platform configurations** → **Web**, add redirect URIs: + - `http://localhost:5000/signin-microsoft` (local development) + - `https:///signin-microsoft` (deployed environments) +3. Note the **Application (client) ID** and **Directory (tenant) ID** from the **Overview** page +4. Under **Certificates & secrets**, create a client secret -After the first `aspire deploy` completes and Azure resources are provisioned, complete these one-time setup steps: +For single-tenant apps, the tenant ID must be configured — the default `/common` endpoint is not supported. -## 1. Register Redirect URIs in Microsoft Entra +# Secrets Management -Go to the [Azure Portal](https://portal.azure.com) > App registrations > your app > Authentication > Add a platform (Web): +Secrets are managed via `dotnet user-secrets` locally and GitHub secrets in CI/CD. -- Add redirect URI: `https:///signin-microsoft` -- The ACA domain is shown in the deploy output (e.g., `memex-test.whiteplant-79bbc284.swedencentral.azurecontainerapps.io`) -- If using a custom domain, add that redirect URI as well +Required secrets for distributed modes: -## 2. Allow-list pgvector Extension on Azure PostgreSQL +| Secret | Description | +|--------|-------------| +| `Parameters:azure-foundry-key` | Azure AI Foundry API key (LLM access) | +| `Parameters:embedding-endpoint` | Embedding model endpoint | +| `Parameters:embedding-key` | Embedding model API key | +| `Parameters:embedding-model` | Embedding model name | +| `Parameters:microsoft-client-id` | Microsoft OAuth client ID | +| `Parameters:microsoft-client-secret` | Microsoft OAuth client secret | +| `Parameters:microsoft-tenant-id` | Microsoft Entra tenant ID (single-tenant apps) | +| `Parameters:google-client-id` | Google OAuth client ID | +| `Parameters:google-client-secret` | Google OAuth client secret | +| `Parameters:custom-domain` | Custom domain for deployed portal | +| `Parameters:certificate-name` | TLS certificate name for custom domain | -Azure PostgreSQL Flexible Server requires explicit extension allow-listing. Without this, the database migration fails silently on vector-related operations: +For `local-test` and `local-prod` modes, also set: -```bash -az postgres flexible-server parameter set \ - --resource-group \ - --server-name \ - --name azure.extensions \ - --value "vector" -``` +| Secret | Description | +|--------|-------------| +| `ConnectionStrings:memex` | Azure PostgreSQL connection string | -Find the server name in the Azure portal or from the Aspire deployment output. - -## 3. Restart the Database Migration - -After allow-listing pgvector, restart the `db-migration` container app so it re-runs schema initialization: +Set secrets using: ```bash -az containerapp revision restart \ - --name db-migration \ - --resource-group \ - --revision +cd memex/aspire/Memex.AppHost +dotnet user-secrets set "Parameters:azure-foundry-key" "" ``` -Or redeploy via `aspire deploy` which rebuilds and redeploys all container apps. - -# Troubleshooting - -## "Failed to read input in non-interactive mode" -All parameters must be set via `dotnet user-secrets` before deploying. Also ensure you pass `-e Development` to `aspire deploy` — without it, user secrets are not loaded. Run `dotnet user-secrets list --project memex/aspire/Memex.AppHost` to check which are missing. - -## Aspire deployment state cache -`aspire deploy` caches parameter values in `~/.aspire/deployments//development.json`. If you update a secret via `dotnet user-secrets`, the cached value is **not** automatically refreshed. To force a refresh, either: -- Delete the cache file and redeploy (Aspire will re-read from user secrets) -- Manually edit the `Parameters` section in the cached JSON file - -## Container App not reachable after deploy -Check that `UseForwardedHeaders()` is enabled in `MemexConfiguration.cs` — Azure Container Apps uses a reverse proxy that sets `X-Forwarded-*` headers. Without forwarded headers, HTTPS redirects and OAuth callbacks fail. - -## Microsoft login: AADSTS50194 (not configured as multi-tenant) -The app registration is single-tenant but the OIDC authority URL defaults to `/common`. Set the `microsoft-tenant-id` parameter to your Entra tenant GUID (see Secrets Reference). Without it, the AppHost defaults to `common` (multi-tenant). - -## Microsoft login: AADSTS50011 (redirect URI mismatch) -The ACA URL must be registered as a redirect URI in the Microsoft Entra app registration. Add `https:///signin-microsoft` under Authentication > Web > Redirect URIs. - -## Microsoft login: AADSTS7000215 (invalid client secret) -Two common causes: -1. **Secret ID vs secret value**: The `microsoft-client-secret` parameter must be the secret **value** (shown once at creation), not the secret **ID** (a GUID). -2. **Stale deployment cache**: Even after updating `dotnet user-secrets`, the old value may persist in `~/.aspire/deployments/`. See "Aspire deployment state cache" above. - -## Microsoft login redirects to blank page -Ensure the redirect URI `https:///signin-microsoft` is registered in the Microsoft Entra app registration. The portal constructs this from the forwarded host header. - -## "function rebuild_user_effective_permissions() does not exist" -The database migration (`db-migration` container app) failed before creating schema functions. Common cause: pgvector extension was not allow-listed on Azure PostgreSQL (see First-Time Deployment Checklist above). Check db-migration logs, fix the root cause, and redeploy. +# Project Structure -## Sample data (ACME, Northwind, etc.) missing in deployed environment -Sample data nodes are loaded from `samples/Graph/Data/` via `AddGraph()`. Verify the container image includes these files and that the portal starts successfully (check Application Insights logs). +``` +memex/aspire/ +├── Memex.AppHost/ # Aspire orchestrator (defines all resources) +├── Memex.Portal.Distributed/ # Portal with co-hosted Orleans silo +├── Memex.Portal.Orleans/ # Orleans grain interfaces +├── Memex.Portal.ServiceDefaults/ # Shared service defaults (health, telemetry) +└── Memex.Database.Migration/ # Database migration project +``` From 415bea42456aa20da1c783b9540943d69f4a6d8e Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Tue, 14 Apr 2026 16:58:50 +0200 Subject: [PATCH 09/14] removal of diagnostic code; clean up --- memex/Memex.Portal.Monolith/Program.cs | 13 -- .../Memex.Portal.Shared/MemexConfiguration.cs | 11 -- .../Data/Architecture/Deployment.md | 20 +-- .../UserNodeTypePermissionTest.cs | 138 ++++++++++++++++++ .../NonfileRouteConstraintTest.cs | 84 +++++++++++ .../UserContextMiddlewareExclusionTest.cs | 86 +++++++++++ 6 files changed, 309 insertions(+), 43 deletions(-) create mode 100644 test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs create mode 100644 test/MeshWeaver.Hosting.Blazor.Test/NonfileRouteConstraintTest.cs create mode 100644 test/MeshWeaver.Hosting.Blazor.Test/UserContextMiddlewareExclusionTest.cs diff --git a/memex/Memex.Portal.Monolith/Program.cs b/memex/Memex.Portal.Monolith/Program.cs index 9544b3e33..a6efc6769 100644 --- a/memex/Memex.Portal.Monolith/Program.cs +++ b/memex/Memex.Portal.Monolith/Program.cs @@ -68,19 +68,6 @@ var app = builder.Build(); -// DIAGNOSTIC — remove after fix confirmed -try -{ - var factories = app.Services.GetServices().ToList(); - Console.WriteLine($"[DIAG] IChatClientFactory count from root DI: {factories.Count}"); - foreach (var f in factories) - Console.WriteLine($"[DIAG] {f.GetType().Name}: Name={f.Name}, Models=[{string.Join(", ", f.Models)}], Order={f.Order}"); -} -catch (Exception ex) -{ - Console.WriteLine($"[DIAG] IChatClientFactory resolution FAILED: {ex.GetType().Name}: {ex.Message}\n{ex}"); -} - // Map Aspire default endpoints (health checks) app.MapDefaultEndpoints(); diff --git a/memex/Memex.Portal.Shared/MemexConfiguration.cs b/memex/Memex.Portal.Shared/MemexConfiguration.cs index 81d308bf5..19c0cd53b 100644 --- a/memex/Memex.Portal.Shared/MemexConfiguration.cs +++ b/memex/Memex.Portal.Shared/MemexConfiguration.cs @@ -92,17 +92,6 @@ public static void ConfigureMemexServices(this WebApplicationBuilder builder) services.AddAzureFoundry(config => builder.Configuration.GetSection("AzureAIS").Bind(config)); - // DIAGNOSTIC — remove after fix confirmed - { - var probe = new MeshWeaver.AI.AzureFoundry.AzureFoundryConfiguration(); - builder.Configuration.GetSection("AzureAIS").Bind(probe); - Console.WriteLine( - $"[DIAG:AzureAIS] Endpoint={probe.Endpoint ?? "(null)"}, " + - $"ApiKey={(!string.IsNullOrEmpty(probe.ApiKey) ? "SET" : "MISSING")}, " + - $"Models.Length={probe.Models.Length}: [{string.Join(", ", probe.Models)}], " + - $"Order={probe.Order}"); - } - services.AddAzureOpenAI(config => builder.Configuration.GetSection("AzureOpenAIS").Bind(config)); diff --git a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md index efe0a5b05..c697ca78f 100644 --- a/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md +++ b/src/MeshWeaver.Documentation/Data/Architecture/Deployment.md @@ -14,8 +14,6 @@ The AppHost supports multiple modes, passed as `--mode `: | Mode | PostgreSQL | Blob Storage | Orleans | Portal Name | |-------------|------------------------------|-------------------------------|-----------|-----------------| | `local` | Docker pgvector container | Emulated (Azurite) | Emulated | memex-local | -| `local-test`| Azure (memex-test) | Azure (meshweavermemextest) | Emulated | memex-local | -| `local-prod`| Azure (memex) | Azure (meshweavermemex) | Emulated | memex-local | | `test` | Azure (memex-test) | Azure (meshweavermemextest) | Azure | memex-test | | `prod` | Azure (memex) | Azure (meshweavermemex) | Azure | memex-prod | | `monolith` | FileSystem (standalone) | — | — | memex-monolith | @@ -46,15 +44,6 @@ aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode l This starts in `local` mode by default, using Docker pgvector and emulated Azure services. -To run locally against Azure test or prod databases: - -```bash -aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode local-test -aspire run --project memex/aspire/Memex.AppHost/Memex.AppHost.csproj -- --mode local-prod -``` - -These modes connect to Azure PostgreSQL and Blob Storage while keeping Orleans emulated locally. - # Monolith Mode For standalone development without Orleans or external infrastructure: @@ -79,7 +68,6 @@ Deployed modes (`test`, `prod`) run on **Azure Container Apps** in Sweden Centra - **Local**: Docker container with pgvector extension (`pgvector/pgvector:pg17`) - **Deployed**: Azure PostgreSQL Flexible Server with pgvector, provisioned automatically -- **local-test/local-prod**: Connects to existing Azure PostgreSQL via connection string ## Azure Blob Storage @@ -92,7 +80,7 @@ Content files (attachments, documents) are stored in Azure Blob Storage. Orleans provides distributed actor clustering for the microservices deployment. -- **Local/local-test/local-prod**: Emulated (in-process) +- **Local**: Emulated (in-process) - **Deployed**: Azure Table Storage for clustering, Azure Blob Storage for grain state ## Application Insights @@ -132,12 +120,6 @@ Required secrets for distributed modes: | `Parameters:custom-domain` | Custom domain for deployed portal | | `Parameters:certificate-name` | TLS certificate name for custom domain | -For `local-test` and `local-prod` modes, also set: - -| Secret | Description | -|--------|-------------| -| `ConnectionStrings:memex` | Azure PostgreSQL connection string | - Set secrets using: ```bash diff --git a/test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs b/test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs new file mode 100644 index 000000000..ad65ac370 --- /dev/null +++ b/test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs @@ -0,0 +1,138 @@ +using System.Threading.Tasks; +using FluentAssertions; +using MeshWeaver.Graph.Configuration; +using MeshWeaver.Mesh; +using MeshWeaver.Mesh.Security; +using MeshWeaver.Mesh.Services; +using MeshWeaver.Messaging; +using Xunit; + +namespace MeshWeaver.Graph.Test; + +public class UserNodeTypePermissionTest +{ + private static MessageHubConfiguration BuildUserHubConfig() + { + var config = new MessageHubConfiguration(null, new Address("User", "Alice")); + var meshNode = UserNodeType.CreateMeshNode(); + return meshNode.HubConfiguration(config); + } + + private static NodeValidationContext ReadContext(string id, string ns) => + new() + { + Operation = NodeOperation.Read, + Node = new MeshNode(id, ns) + }; + + private static NodeValidationContext UpdateContext(string id, string ns) => + new() + { + Operation = NodeOperation.Update, + Node = new MeshNode(id, ns) + }; + + #region Hub Permission Rules + + [Fact] + public void AuthenticatedUser_HasHubReadPermission() + { + var config = BuildUserHubConfig(); + var ruleSet = config.Get(); + ruleSet.Should().NotBeNull("UserNodeType should register hub permission rules"); + + ruleSet!.HasPermission(Permission.Read, null!, "alice") + .Should().BeTrue("any authenticated user should have Read permission"); + } + + [Fact] + public void UnauthenticatedUser_DeniedHubReadPermission() + { + var config = BuildUserHubConfig(); + var ruleSet = config.Get(); + ruleSet.Should().NotBeNull(); + + ruleSet!.HasPermission(Permission.Read, null!, null) + .Should().BeFalse("unauthenticated (null userId) should be denied"); + + ruleSet.HasPermission(Permission.Read, null!, "") + .Should().BeFalse("unauthenticated (empty userId) should be denied"); + } + + #endregion + + #region Node Access Rules (via NodeAccessRuleSet) + + [Fact] + public async Task AuthenticatedUser_CanReadDirectUserNode() + { + var config = BuildUserHubConfig(); + var ruleSet = config.Get(); + ruleSet.Should().NotBeNull("UserNodeType should register node access rules"); + + var accessRule = ruleSet!.ToAccessRule(UserNodeType.NodeType); + // Path = "User/Alice" (derived from ns/id) + var context = ReadContext("Alice", "User"); + + var result = await accessRule.HasAccessAsync(context, "bob"); + result.Should().BeTrue("any authenticated user can read a direct User node"); + } + + [Fact] + public async Task UnauthenticatedUser_CannotReadDirectUserNode() + { + var config = BuildUserHubConfig(); + var ruleSet = config.Get(); + var accessRule = ruleSet!.ToAccessRule(UserNodeType.NodeType); + + var context = ReadContext("Alice", "User"); + + var resultNull = await accessRule.HasAccessAsync(context, null); + resultNull.Should().BeFalse("unauthenticated user (null) should be denied"); + + var resultEmpty = await accessRule.HasAccessAsync(context, ""); + resultEmpty.Should().BeFalse("unauthenticated user (empty) should be denied"); + } + + [Fact] + public async Task AuthenticatedUser_CannotReadChildNode() + { + var config = BuildUserHubConfig(); + var ruleSet = config.Get(); + var accessRule = ruleSet!.ToAccessRule(UserNodeType.NodeType); + + // Path = "User/Alice/thread1" (child node) + var context = ReadContext("thread1", "User/Alice"); + + var result = await accessRule.HasAccessAsync(context, "bob"); + result.Should().BeFalse("child nodes (threads, activities) should not be publicly readable"); + } + + [Fact] + public async Task UserCanEditOwnNode() + { + var config = BuildUserHubConfig(); + var ruleSet = config.Get(); + var accessRule = ruleSet!.ToAccessRule(UserNodeType.NodeType); + + var context = UpdateContext("Alice", "User"); + + var result = await accessRule.HasAccessAsync(context, "Alice"); + result.Should().BeTrue("users should be able to edit their own node"); + } + + [Fact] + public async Task UserCannotEditOtherUserNode() + { + var config = BuildUserHubConfig(); + var ruleSet = config.Get(); + var accessRule = ruleSet!.ToAccessRule(UserNodeType.NodeType); + + var context = UpdateContext("Alice", "User"); + + var result = await accessRule.HasAccessAsync(context, "Bob"); + result.Should().BeFalse("users should not be able to edit other users' nodes"); + } + + #endregion +} diff --git a/test/MeshWeaver.Hosting.Blazor.Test/NonfileRouteConstraintTest.cs b/test/MeshWeaver.Hosting.Blazor.Test/NonfileRouteConstraintTest.cs new file mode 100644 index 000000000..25195dc20 --- /dev/null +++ b/test/MeshWeaver.Hosting.Blazor.Test/NonfileRouteConstraintTest.cs @@ -0,0 +1,84 @@ +using FluentAssertions; +using MeshWeaver.Blazor.Infrastructure; +using Microsoft.AspNetCore.Routing; +using Xunit; + +namespace MeshWeaver.Hosting.Blazor.Test; + +public class NonfileRouteConstraintTest +{ + private readonly NonfileRouteConstraint _constraint = new(); + + private bool Match(string path) + { + var values = new RouteValueDictionary { ["Path"] = path }; + return _constraint.Match(null, null, "Path", values, RouteDirection.IncomingRequest); + } + + [Theory] + [InlineData("signin-microsoft")] + [InlineData("signin-google")] + [InlineData("signin-linkedin")] + [InlineData("signin-apple")] + [InlineData("signin-microsoft/callback")] + [InlineData("signin-google/callback")] + public void OAuthCallbackPaths_AreExcluded(string path) + { + Match(path).Should().BeFalse(because: $"'{path}' is an OAuth callback and should be excluded"); + } + + [Theory] + [InlineData("_framework")] + [InlineData("_framework/blazor.web.js")] + [InlineData("_content")] + [InlineData("_content/MeshWeaver.Blazor/css/app.css")] + [InlineData("_blazor")] + [InlineData("favicon.ico")] + [InlineData("auth")] + [InlineData("auth/login")] + [InlineData("dev")] + [InlineData("dev/login")] + [InlineData("mcp")] + [InlineData("mcp/sse")] + public void StaticAndInfrastructurePaths_AreExcluded(string path) + { + Match(path).Should().BeFalse(because: $"'{path}' should be excluded"); + } + + [Theory] + [InlineData("ACME/Overview")] + [InlineData("User/Alice")] + [InlineData("Northwind/Dashboard")] + [InlineData("Doc/Architecture")] + [InlineData("Organization/Search")] + public void NormalApplicationPaths_PassThrough(string path) + { + Match(path).Should().BeTrue(because: $"'{path}' is a normal route and should pass through"); + } + + [Fact] + public void EmptyPath_ReturnsTrue() + { + var values = new RouteValueDictionary { ["Path"] = "" }; + _constraint.Match(null, null, "Path", values, RouteDirection.IncomingRequest) + .Should().BeTrue(); + } + + [Fact] + public void MissingRouteValue_ReturnsTrue() + { + var values = new RouteValueDictionary(); + _constraint.Match(null, null, "Path", values, RouteDirection.IncomingRequest) + .Should().BeTrue(); + } + + [Theory] + [InlineData("SIGNIN-MICROSOFT")] + [InlineData("Signin-Google")] + [InlineData("_FRAMEWORK")] + [InlineData("_Content")] + public void ExcludedPaths_AreCaseInsensitive(string path) + { + Match(path).Should().BeFalse(because: "exclusion should be case-insensitive"); + } +} diff --git a/test/MeshWeaver.Hosting.Blazor.Test/UserContextMiddlewareExclusionTest.cs b/test/MeshWeaver.Hosting.Blazor.Test/UserContextMiddlewareExclusionTest.cs new file mode 100644 index 000000000..5f2139363 --- /dev/null +++ b/test/MeshWeaver.Hosting.Blazor.Test/UserContextMiddlewareExclusionTest.cs @@ -0,0 +1,86 @@ +using System; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging.Abstractions; +using MeshWeaver.Blazor.Infrastructure; +using Xunit; + +namespace MeshWeaver.Hosting.Blazor.Test; + +public class UserContextMiddlewareExclusionTest +{ + [Theory] + [InlineData("/_framework/blazor.web.js")] + [InlineData("/_content/MeshWeaver.Blazor/css/app.css")] + [InlineData("/_blazor/negotiate")] + [InlineData("/static/images/logo.png")] + [InlineData("/favicon.ico")] + public async Task ExcludedPrefixes_SkipUserResolution(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var logger = NullLogger.Instance; + var middleware = new UserContextMiddleware(next, logger); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + + // Should call next() without trying to resolve PortalApplication + // (which isn't registered, so it would throw if it tried) + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: $"'{path}' should be skipped and pass through to next"); + } + + [Theory] + [InlineData("/ACME/Overview")] + [InlineData("/User/Alice")] + [InlineData("/")] + public async Task NonExcludedPaths_AttemptUserResolution(string path) + { + RequestDelegate next = _ => Task.CompletedTask; + + var logger = NullLogger.Instance; + var middleware = new UserContextMiddleware(next, logger); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + + // Non-excluded paths will attempt to resolve PortalApplication from DI. + // Since RequestServices isn't set up, this throws (proving the path was NOT skipped). + var act = () => middleware.InvokeAsync(context); + await act.Should().ThrowAsync( + because: "non-excluded paths should attempt PortalApplication resolution"); + } + + [Theory] + [InlineData("/_FRAMEWORK/blazor.web.js")] + [InlineData("/_Content/something")] + [InlineData("/Static/image.png")] + [InlineData("/FAVICON.ICO")] + public async Task ExcludedPrefixes_AreCaseInsensitive(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var logger = NullLogger.Instance; + var middleware = new UserContextMiddleware(next, logger); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: "exclusion should be case-insensitive"); + } +} From 19d209f95bde8c22fbc3277ce9eb7ef90d51fd12 Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Mon, 20 Apr 2026 13:56:45 +0200 Subject: [PATCH 10/14] Revert "Merge pull request #94 from Systemorph/fix/sample-org-search-visibility" This reverts commit f5dac08bc7b63d65fae1084c6d60c5706d8c5007, reversing changes made to 05ba282611fbaea8984c3b945fa4505fb086b5a1. --- samples/Graph/Data/ACME/index.md | 2 +- samples/Graph/Data/Cornerstone/index.md | 2 +- samples/Graph/Data/Northwind/index.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/Graph/Data/ACME/index.md b/samples/Graph/Data/ACME/index.md index 5ebe8d823..e08bdb8e3 100644 --- a/samples/Graph/Data/ACME/index.md +++ b/samples/Graph/Data/ACME/index.md @@ -1,5 +1,5 @@ --- -NodeType: Markdown +NodeType: Organization Name: ACME Category: Task Management Description: Project and task management demo showcasing MeshWeaver's collaborative workflows and AI agent integration diff --git a/samples/Graph/Data/Cornerstone/index.md b/samples/Graph/Data/Cornerstone/index.md index 7633c3a19..ddf8c725e 100644 --- a/samples/Graph/Data/Cornerstone/index.md +++ b/samples/Graph/Data/Cornerstone/index.md @@ -1,5 +1,5 @@ --- -NodeType: Markdown +NodeType: Organization Name: Cornerstone Category: Insurance Description: Reinsurance pricing demo showcasing property risk management, geographic visualization, and Excel data import diff --git a/samples/Graph/Data/Northwind/index.md b/samples/Graph/Data/Northwind/index.md index 3e92fe550..ac71fb0ff 100644 --- a/samples/Graph/Data/Northwind/index.md +++ b/samples/Graph/Data/Northwind/index.md @@ -1,5 +1,5 @@ --- -NodeType: Markdown +NodeType: Organization Name: Northwind Category: Analytics Description: Gourmet food distribution analytics demonstrating MeshWeaver's data visualization and AI-assisted exploration capabilities From 64835dd7f93339526cd91f68c7381cab4e754d37 Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Mon, 20 Apr 2026 15:22:32 +0200 Subject: [PATCH 11/14] chore: expand Azure CLI permission rules in Claude settings Co-Authored-By: Claude Opus 4.6 --- .claude/settings.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.claude/settings.json b/.claude/settings.json index 73b5e89b5..457cfd108 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -5,15 +5,26 @@ "Bash(aspire mcp:*)", "Bash(az account:*)", "Bash(az containerapp * list:*)", + "Bash(az containerapp * logs:*)", "Bash(az containerapp * show:*)", + "Bash(az containerapp list:*)", "Bash(az containerapp logs:*)", + "Bash(az containerapp show:*)", + "Bash(az group list:*)", + "Bash(az group show:*)", "Bash(az monitor * list:*)", "Bash(az monitor * show:*)", "Bash(az monitor activity-log:*)", + "Bash(az monitor list:*)", "Bash(az monitor log-analytics query:*)", "Bash(az monitor metrics:*)", + "Bash(az monitor show:*)", "Bash(az postgres * list:*)", "Bash(az postgres * show:*)", + "Bash(az postgres list:*)", + "Bash(az postgres show:*)", + "Bash(az resource list:*)", + "Bash(az resource show:*)", "Bash(cat:*)", "Bash(claude:*)", "Bash(cmp:*)", @@ -107,6 +118,7 @@ ], "deny": [ "Bash(az group delete:*)", + "Bash(az resource delete:*)", "Bash(git push --force:*)", "Bash(git push -f:*)", "Bash(git reset --hard:*)", From 1b49632aa423f8786552cc2891d5886ebaee3ffe Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Wed, 22 Apr 2026 23:25:45 +0200 Subject: [PATCH 12/14] fixes to login and AI chats --- MeshWeaver.slnx | 1 + memex/aspire/Memex.AppHost/Program.cs | 4 +- .../Memex.Database.Migration/Program.cs | 192 +++++++++--------- .../Memex.Portal.Distributed/appsettings.json | 4 +- .../Chat/ThreadChatView.razor.cs | 152 +++++++------- .../CircuitAccessHandler.cs | 21 +- .../Security/SecurityService.cs | 18 ++ .../Memex.Portal.Shared.Test.csproj | 6 + .../OnboardingMiddlewareExclusionTest.cs | 140 +++++++++++++ .../VirtualUserMiddlewareExclusionTest.cs | 103 ++++++++++ .../AccessControlPipelineTest.cs | 156 ++++++++++++++ 11 files changed, 623 insertions(+), 174 deletions(-) create mode 100644 test/Memex.Portal.Shared.Test/Memex.Portal.Shared.Test.csproj create mode 100644 test/Memex.Portal.Shared.Test/OnboardingMiddlewareExclusionTest.cs create mode 100644 test/Memex.Portal.Shared.Test/VirtualUserMiddlewareExclusionTest.cs diff --git a/MeshWeaver.slnx b/MeshWeaver.slnx index ff9776e06..52e80bbad 100644 --- a/MeshWeaver.slnx +++ b/MeshWeaver.slnx @@ -145,6 +145,7 @@ + diff --git a/memex/aspire/Memex.AppHost/Program.cs b/memex/aspire/Memex.AppHost/Program.cs index 1e9e7a291..b995294e4 100644 --- a/memex/aspire/Memex.AppHost/Program.cs +++ b/memex/aspire/Memex.AppHost/Program.cs @@ -143,6 +143,7 @@ .WithEnvironment("Anthropic__Models__0", "claude-sonnet-4-6") .WithEnvironment("Anthropic__Models__1", "claude-opus-4-7") .WithEnvironment("Anthropic__Models__2", "claude-haiku-4-5") + .WithEnvironment("Anthropic__Order", "1") // Model tiers: map agent tiers to concrete models .WithEnvironment("ModelTier__Heavy", "claude-opus-4-7") .WithEnvironment("ModelTier__Standard", "claude-sonnet-4-6") @@ -152,6 +153,7 @@ .WithEnvironment("AzureOpenAIS__ApiKey", azureFoundryKey) .WithEnvironment("AzureOpenAIS__Models__0", "gpt-5-mini") .WithEnvironment("AzureOpenAIS__Models__1", "gpt-5.4") + .WithEnvironment("AzureOpenAIS__Order", "2") // LLM: Azure AI Foundry (multi-model inference endpoint) .WithEnvironment("AzureAIS__Endpoint", "https://fy-meshweaver3-dev-swc-001.services.ai.azure.com/models") .WithEnvironment("AzureAIS__ApiKey", azureFoundryKey) @@ -159,7 +161,7 @@ .WithEnvironment("AzureAIS__Models__1", "gpt-5.3-codex") .WithEnvironment("AzureAIS__Models__2", "Mistral-Large-3") .WithEnvironment("AzureAIS__Models__3", "DeepSeek-V3.2") - .WithEnvironment("AzureAIS__Order", "1") + .WithEnvironment("AzureAIS__Order", "0") // Authentication .WithEnvironment("Authentication__EnableDevLogin", mode != "prod" ? "true" : "false") .WithEnvironment("Authentication__Microsoft__ClientId", microsoftClientId) diff --git a/memex/aspire/Memex.Database.Migration/Program.cs b/memex/aspire/Memex.Database.Migration/Program.cs index aa0fbe18e..530b38734 100644 --- a/memex/aspire/Memex.Database.Migration/Program.cs +++ b/memex/aspire/Memex.Database.Migration/Program.cs @@ -7,10 +7,12 @@ using MeshWeaver.Mesh; using Npgsql; +Console.WriteLine("[Migration] Starting..."); var builder = Host.CreateApplicationBuilder(args); builder.AddServiceDefaults(); var connectionString = builder.Configuration.GetConnectionString("memex") ?? ""; +Console.WriteLine($"[Migration] ConnectionString: {(string.IsNullOrEmpty(connectionString) ? "(empty)" : connectionString[..Math.Min(30, connectionString.Length)] + "...")}"); if (connectionString.Contains("database.azure.com")) builder.AddAzureNpgsqlDataSource("memex"); else @@ -24,10 +26,14 @@ o.VectorDimensions = embeddingOptions.Dimensions; }); +Console.WriteLine("[Migration] Building host..."); var host = builder.Build(); +Console.WriteLine("[Migration] Host built. Resolving services..."); var logger = host.Services.GetRequiredService().CreateLogger("Migration"); +Console.WriteLine("[Migration] Resolving NpgsqlDataSource..."); var dataSource = host.Services.GetRequiredService(); +Console.WriteLine("[Migration] NpgsqlDataSource resolved."); var options = host.Services.GetRequiredService>(); logger.LogInformation("Running database migration..."); @@ -36,7 +42,7 @@ // (portal, migration) can create per-organization schemas at runtime. if (connectionString.Contains("database.azure.com")) { - var dbName = new NpgsqlConnectionStringBuilder(connectionString).Database ?? "memex"; + var dbName = new NpgsqlConnectionStringBuilder(connectionString).Database; await using var grantCmd = dataSource.CreateCommand( $"GRANT CREATE ON DATABASE \"{dbName}\" TO azure_pg_admin"); await grantCmd.ExecuteNonQueryAsync(); @@ -117,7 +123,7 @@ AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' if (isFreshDb) { logger.LogInformation("Fresh database detected — skipping data repairs (no existing data to fix)."); - currentVersion = 5; // Skip all repair migrations (no existing data to fix) + currentVersion = 1; // Skip all repair migrations } // ── Data repair v1: Move AccessAssignments to correct table + namespace ── @@ -392,7 +398,7 @@ IF NOT assignment_exists THEN 'User/' || user_rec.id, NOW(), 1, - 2 + 'Active' ); RAISE NOTICE 'Created self-assignment for user %', user_rec.id; END IF; @@ -428,104 +434,108 @@ EXCEPTION WHEN OTHERS THEN logger.LogInformation("Repair v5 completed."); } -// ── Data repair v6: Rebuild user_effective_permissions for all schemas ── -// Ensures self-assignments and permissions are correct after fresh deployments, -// schema re-initialization, or any silent failure in UserScopeGrantHandler. -// This runs on fresh DBs (currentVersion=5 is set, not 6) and existing DBs alike. +// ── Data repair v6: Fix search_across_schemas to enforce partition_access ── +// Bug: public_read node types bypassed partition_access entirely, leaking +// cross-partition data in search (e.g., meshweaver user could see PartnerRe). +// Fix: partition_access is now always required; public_read only skips +// node-level permission checks within accessible partitions. +// The stored proc is re-created by InitializePublicSchemaAsync (idempotent). if (currentVersion < 6) { - logger.LogInformation("Running repair v6: Ensure user self-assignments and rebuild all permissions..."); - await using (var cmd = dataSource.CreateCommand(""" - DO $$ - DECLARE - user_rec RECORD; - schema_rec RECORD; - assignment_exists BOOLEAN; - user_schema_exists BOOLEAN; - BEGIN - -- Guard: user schema may not exist on fresh DBs - SELECT EXISTS( - SELECT 1 FROM information_schema.schemata - WHERE schema_name = 'user' - ) INTO user_schema_exists; - - IF user_schema_exists THEN - -- Ensure every User node has an Admin self-assignment - FOR user_rec IN - SELECT id FROM "user".mesh_nodes WHERE node_type = 'User' - LOOP - SELECT EXISTS( - SELECT 1 FROM "user".access - WHERE namespace = 'User/' || user_rec.id || '/_Access' - AND content->>'accessObject' = user_rec.id - ) INTO assignment_exists; - - IF NOT assignment_exists THEN - INSERT INTO "user".access (id, namespace, name, node_type, content, main_node, last_modified, version, state) - VALUES ( - user_rec.id || '_SelfAccess', - 'User/' || user_rec.id || '/_Access', - user_rec.id || ' Self Access', - 'AccessAssignment', - jsonb_build_object( - 'accessObject', user_rec.id, - 'displayName', user_rec.id, - 'roles', jsonb_build_array(jsonb_build_object('role', 'Admin')) - ), - 'User/' || user_rec.id, - NOW(), 1, 2 - ); - RAISE NOTICE 'v6: Created self-assignment for user %', user_rec.id; - END IF; - END LOOP; - - -- Rebuild permissions for user schema - BEGIN - PERFORM "user".rebuild_user_effective_permissions(); - RAISE NOTICE 'v6: Rebuilt permissions for user schema'; - EXCEPTION WHEN OTHERS THEN - RAISE NOTICE 'v6: user schema rebuild failed: %', SQLERRM; - END; - ELSE - RAISE NOTICE 'v6: user schema does not exist yet — skipping (trigger will handle first login)'; - END IF; + logger.LogInformation("Running repair v6: Fix search_across_schemas access control..."); + // Re-create the stored procedure with fixed access control logic + await PostgreSqlSchemaInitializer.InitializePartitionAccessTableAsync(dataSource); + currentVersion = 6; + logger.LogInformation("Repair v6 completed — search_across_schemas updated."); +} - -- Rebuild permissions for all other content schemas - FOR schema_rec IN - SELECT schema_name FROM information_schema.schemata s - WHERE EXISTS (SELECT 1 FROM information_schema.tables t - WHERE t.table_schema = s.schema_name AND t.table_name = 'access') - AND s.schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast', 'user') - AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' - LOOP - BEGIN - EXECUTE format('SELECT %I.rebuild_user_effective_permissions()', schema_rec.schema_name); - RAISE NOTICE 'v6: Rebuilt permissions for schema %', schema_rec.schema_name; - EXCEPTION WHEN OTHERS THEN - RAISE NOTICE 'v6: Schema % rebuild failed: %', schema_rec.schema_name, SQLERRM; - END; - END LOOP; - END $$; +// ── Data repair v7: Deploy per-user permission rebuild trigger ── +// The trigger function trg_access_changed() previously called rebuild_user_effective_permissions() +// which rebuilds ALL users' permissions — causing deadlocks under concurrent access. +// New trigger calls rebuild_user_permissions_for(affected_user) — only touches one user's rows. +// The schema initializer already creates the new functions; we just need to re-run schema init +// per partition to deploy the updated trigger function. +if (currentVersion < 7) +{ + logger.LogInformation("Running repair v7: Deploy per-user permission rebuild trigger..."); + + var schemas = new List(); + await using (var listCmd = dataSource.CreateCommand(""" + SELECT schema_name FROM information_schema.schemata s + WHERE EXISTS (SELECT 1 FROM information_schema.tables t WHERE t.table_schema = s.schema_name AND t.table_name = 'access') + AND s.schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast') + AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' + ORDER BY s.schema_name """)) { - await cmd.ExecuteNonQueryAsync(); + await using var rdr = await listCmd.ExecuteReaderAsync(); + while (await rdr.ReadAsync()) schemas.Add(rdr.GetString(0)); } - currentVersion = 6; - logger.LogInformation("Repair v6 completed."); -} + foreach (var schema in schemas) + { + logger.LogInformation("Repair v7: Updating trigger functions for schema {Schema}...", schema); + var csb = new NpgsqlConnectionStringBuilder(connectionString) { SearchPath = $"{schema},public" }; + var dsb = new NpgsqlDataSourceBuilder(csb.ConnectionString); + dsb.UseVector(); + await using var schemaDs = dsb.Build(); -// ── Always: rebuild user_effective_permissions to catch any new logins since last deploy ── -try -{ - await using var rebuildCmd = dataSource.CreateCommand( - "SELECT \"user\".rebuild_user_effective_permissions()"); - await rebuildCmd.ExecuteNonQueryAsync(); - logger.LogInformation("Rebuilt user_effective_permissions for user schema."); + var schemaOpts = new PostgreSqlStorageOptions + { + ConnectionString = csb.ConnectionString, + VectorDimensions = options.Value.VectorDimensions, + Schema = schema + }; + + await PostgreSqlSchemaInitializer.InitializeMeshTablesAsync(schemaDs, schemaOpts); + logger.LogInformation("Repair v7: Schema {Schema} — trigger updated", schema); + } + + currentVersion = 7; + logger.LogInformation("Repair v7 completed."); } -catch (Exception ex) + +// ── Data repair v8: Fix ThreadMessage MainNode ── +// Thread message nodes created from the UI may have MainNode set to the thread path +// (e.g., "Org/_Thread/thread-id") instead of the thread's content node (e.g., "Org"). +// This causes "Access denied" because SatelliteAccessRule delegates to MainNode. +// Fix: set MainNode = the part before "/_Thread/" for all ThreadMessage nodes. +if (currentVersion < 8) { - logger.LogWarning(ex, "Could not rebuild user_effective_permissions (user schema may not exist yet)."); + logger.LogInformation("Running repair v8: Fix ThreadMessage MainNode..."); + var totalFixed = 0; + + var schemas = new List(); + await using (var listCmd = dataSource.CreateCommand(""" + SELECT schema_name FROM information_schema.schemata s + WHERE EXISTS (SELECT 1 FROM information_schema.tables t WHERE t.table_schema = s.schema_name AND t.table_name = 'mesh_nodes') + AND s.schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast', 'admin') + AND s.schema_name NOT LIKE '%\_versions' ESCAPE '\' + ORDER BY s.schema_name + """)) + { + await using var rdr = await listCmd.ExecuteReaderAsync(); + while (await rdr.ReadAsync()) schemas.Add(rdr.GetString(0)); + } + + foreach (var schema in schemas) + { + await using var fixCmd = dataSource.CreateCommand($""" + UPDATE "{schema}".mesh_nodes + SET main_node = split_part(main_node, '/_Thread/', 1) + WHERE node_type = 'ThreadMessage' + AND main_node LIKE '%/_Thread/%' + """); + var affected = await fixCmd.ExecuteNonQueryAsync(); + if (affected > 0) + { + logger.LogInformation("Repair v8: Fixed {Count} ThreadMessage MainNode(s) in schema {Schema}", affected, schema); + totalFixed += affected; + } + } + + currentVersion = 8; + logger.LogInformation("Repair v8 completed — fixed {Total} ThreadMessage MainNode(s)", totalFixed); } // ── Always: populate searchable_schemas from remaining content partitions ── diff --git a/memex/aspire/Memex.Portal.Distributed/appsettings.json b/memex/aspire/Memex.Portal.Distributed/appsettings.json index eba7ad520..71029baf8 100644 --- a/memex/aspire/Memex.Portal.Distributed/appsettings.json +++ b/memex/aspire/Memex.Portal.Distributed/appsettings.json @@ -1,7 +1,9 @@ { "Logging": { "LogLevel": { - "Default": "Warning" + "Default": "Warning", + "MeshWeaver.AI": "Information", + "MeshWeaver.Hosting.Orleans.RoutingGrain": "Information" } }, "AllowedHosts": "*", diff --git a/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor.cs b/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor.cs index 250595e3c..85da1b054 100644 --- a/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor.cs +++ b/src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor.cs @@ -374,87 +374,101 @@ private void SendMessage() private void SubmitMessageCore() { - if (_isDisposed) - return; - - // Use MessageText (updated via Monaco ValueChanged binding) — no blocking Monaco read. - var userMessageText = MessageText; - - // Attempt to begin submission — rejects empty text and concurrent submissions - if (!submissionHandler.TryBeginSubmit(userMessageText)) - return; + try + { + if (_isDisposed) + return; - // Disable input and clear the editor immediately — flush render so spinner shows - MessageText = null; - StateHasChanged(); + // Use MessageText (updated via Monaco ValueChanged binding) — no blocking Monaco read. + var userMessageText = MessageText; - // Fire-and-forget Monaco clear — no await in the submit path. - if (monacoEditor != null) - { - _ = ClearMonacoAsync(); - } + // Attempt to begin submission — rejects empty text and concurrent submissions + if (!submissionHandler.TryBeginSubmit(userMessageText)) + return; - var accessService = Hub.ServiceProvider.GetService(); - var createdBy = accessService?.Context?.ObjectId ?? accessService?.CircuitContext?.ObjectId; - var authorName = accessService?.Context?.Name ?? "You"; - var isCompact = ViewModel.HideEmptyState; - var capturedAttachments = attachments.Select(a => a.Path).ToList(); + // Disable input and clear the editor immediately — flush render so spinner shows + MessageText = null; + StateHasChanged(); - var ctx = new SubmitContext - { - Hub = Hub, - ThreadPath = threadPath, - Namespace = NavigationService.CurrentNamespace ?? initialContext - ?? (!string.IsNullOrEmpty(createdBy) ? $"User/{createdBy}" : "User"), - UserText = userMessageText!, - AgentName = selectedAgentInfo?.Name, - ModelName = selectedModelInfo?.Name, - ContextPath = initialContext, - Attachments = capturedAttachments, - CreatedBy = createdBy, - AuthorName = authorName, - OnError = err => InvokeAsync(() => + // Fire-and-forget Monaco clear — no await in the submit path. + if (monacoEditor != null) { - if (_isDisposed) return; - Logger.LogWarning("[ThreadChat:{InstanceId}] Submit failed: {Error}", _instanceId, err); - showSubmissionProgress = false; - submissionHandler.ForceRelease(); - StateHasChanged(); - }), - OnThreadCreated = node => InvokeAsync(() => + _ = ClearMonacoAsync(); + } + + var accessService = Hub.ServiceProvider.GetService(); + var createdBy = accessService?.Context?.ObjectId ?? accessService?.CircuitContext?.ObjectId; + var authorName = accessService?.Context?.Name ?? "You"; + var isCompact = ViewModel.HideEmptyState; + var capturedAttachments = attachments.Select(a => a.Path).ToList(); + + var ns = !string.IsNullOrEmpty(NavigationService.CurrentNamespace) + ? NavigationService.CurrentNamespace + : !string.IsNullOrEmpty(initialContext) + ? initialContext + : !string.IsNullOrEmpty(createdBy) + ? $"User/{createdBy}" + : "User"; + + var ctx = new SubmitContext { - if (_isDisposed) return; - threadPath = node.Path; - threadName = node.Name; - UpdateSidePanelTitle(); - if (isCompact && !string.IsNullOrEmpty(node.Path)) + Hub = Hub, + ThreadPath = string.IsNullOrEmpty(threadPath) ? null : threadPath, + Namespace = ns, + UserText = userMessageText!, + AgentName = selectedAgentInfo?.Name, + ModelName = selectedModelInfo?.Name, + ContextPath = initialContext, + Attachments = capturedAttachments, + CreatedBy = createdBy, + AuthorName = authorName, + OnError = err => InvokeAsync(() => { - NavigationManager.NavigateTo($"/{node.Path}"); - } - else if (!string.IsNullOrEmpty(node.Path)) + if (_isDisposed) return; + Logger.LogWarning("[ThreadChat:{InstanceId}] Submit failed: {Error}", _instanceId, err); + showSubmissionProgress = false; + submissionHandler.ForceRelease(); + StateHasChanged(); + }), + OnThreadCreated = node => InvokeAsync(() => { - SidePanelState.SetContentPath(node.Path); - } - showSubmissionProgress = false; - StateHasChanged(); - }) - }; + if (_isDisposed) return; + threadPath = node.Path; + threadName = node.Name; + UpdateSidePanelTitle(); + if (isCompact && !string.IsNullOrEmpty(node.Path)) + { + NavigationManager.NavigateTo($"/{node.Path}"); + } + else if (!string.IsNullOrEmpty(node.Path)) + { + SidePanelState.SetContentPath(node.Path); + } + showSubmissionProgress = false; + StateHasChanged(); + }) + }; - if (string.IsNullOrEmpty(threadPath)) - { - showSubmissionProgress = isCompact; - ThreadSubmission.CreateThreadAndSubmit(ctx); + if (string.IsNullOrEmpty(threadPath)) + { + showSubmissionProgress = isCompact; + ThreadSubmission.CreateThreadAndSubmit(ctx); + } + else + { + ThreadSubmission.Submit(ctx); + } + + // Claude-Code-style queue: input stays enabled so the user can keep typing while + // previous submissions are being processed by the thread. The server watcher + // batches unprocessed user messages into a single round. + submissionHandler.ForceRelease(); + StateHasChanged(); } - else + catch (Exception ex) { - ThreadSubmission.Submit(ctx); + Logger.LogError(ex, "[ThreadChat:{InstanceId}] SubmitMessageCore failed", _instanceId); } - - // Claude-Code-style queue: input stays enabled so the user can keep typing while - // previous submissions are being processed by the thread. The server watcher - // batches unprocessed user messages into a single round. - submissionHandler.ForceRelease(); - StateHasChanged(); } private async Task ClearMonacoAsync() diff --git a/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs b/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs index 3086c9b77..1db069691 100644 --- a/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs +++ b/src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs @@ -147,22 +147,19 @@ public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken ct) { try { - // Use IMeshQueryCore (no access control) — this is an infrastructure lookup - // during login, before the user's identity is established. - var queryCore = _hub.ServiceProvider.GetService(); - if (queryCore == null) + // Impersonate as the hub identity for this lookup — the user's access context + // isn't established yet during login, so we use the hub's system-level identity + // to query the User namespace for email-to-ObjectId resolution. + var accessService = _hub.ServiceProvider.GetService(); + if (accessService == null) return null; - var request = new MeshQueryRequest - { - Query = $"$type:MeshNode nodeType:User namespace:User content.email:{email} limit:1" - }; - await foreach (var item in queryCore.QueryAsync(request, _hub.JsonSerializerOptions)) + using (accessService.ImpersonateAsHub(_hub)) { - if (item is MeshNode node) - return node; + var meshService = _hub.ServiceProvider.GetRequiredService(); + return await meshService.QueryAsync( + $"nodeType:User namespace:User content.email:{email} limit:1").FirstOrDefaultAsync(); } - return null; } catch (Exception ex) { diff --git a/src/MeshWeaver.Hosting/Security/SecurityService.cs b/src/MeshWeaver.Hosting/Security/SecurityService.cs index d8a5b102d..c96ad5a0d 100644 --- a/src/MeshWeaver.Hosting/Security/SecurityService.cs +++ b/src/MeshWeaver.Hosting/Security/SecurityService.cs @@ -232,6 +232,24 @@ public async Task GetEffectivePermissionsAsync(string nodePath, stri } } + // Built-in invariant: a user always has Admin on their own User/{userId} scope. + // UserScopeGrantHandler materializes this into the DB for PostgreSQL's materialized view, + // but the in-memory permission check should not depend solely on that materialization. + if (!string.IsNullOrEmpty(userId) + && userId != WellKnownUsers.Anonymous + && userId != WellKnownUsers.Public) + { + var userScopePath = $"User/{userId}"; + if (nodePath.Equals(userScopePath, StringComparison.OrdinalIgnoreCase) + || nodePath.StartsWith(userScopePath + "/", StringComparison.OrdinalIgnoreCase)) + { + if (!roleAssignments.ContainsKey("Admin")) + { + roleAssignments["Admin"] = (Denied: false, Depth: scopes.Count); + } + } + } + // Check Admin scope for PlatformAdmin assignments (global reach). // PlatformAdmin stored at Admin/{userId}_Access should grant access to ALL paths. if (!scopes.Contains("Admin")) diff --git a/test/Memex.Portal.Shared.Test/Memex.Portal.Shared.Test.csproj b/test/Memex.Portal.Shared.Test/Memex.Portal.Shared.Test.csproj new file mode 100644 index 000000000..f5c5b2119 --- /dev/null +++ b/test/Memex.Portal.Shared.Test/Memex.Portal.Shared.Test.csproj @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/Memex.Portal.Shared.Test/OnboardingMiddlewareExclusionTest.cs b/test/Memex.Portal.Shared.Test/OnboardingMiddlewareExclusionTest.cs new file mode 100644 index 000000000..06029a1db --- /dev/null +++ b/test/Memex.Portal.Shared.Test/OnboardingMiddlewareExclusionTest.cs @@ -0,0 +1,140 @@ +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using FluentAssertions; +using Memex.Portal.Shared.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging.Abstractions; +using Xunit; + +namespace Memex.Portal.Shared.Test; + +public class OnboardingMiddlewareExclusionTest +{ + private static ClaimsPrincipal AuthenticatedUser => + new(new ClaimsIdentity("TestAuth")); + + [Theory] + [InlineData("/onboarding")] + [InlineData("/login")] + [InlineData("/auth/callback")] + [InlineData("/_framework/blazor.js")] + [InlineData("/_content/MeshWeaver.Blazor/css/app.css")] + [InlineData("/static/img.png")] + [InlineData("/favicon.ico")] + [InlineData("/mcp")] + [InlineData("/signin-microsoft")] + public async Task ExcludedPrefixes_SkipOnboardingCheck(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var middleware = new OnboardingMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + context.User = AuthenticatedUser; + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: $"'{path}' should be excluded and pass through to next"); + } + + [Theory] + [InlineData("/signin-microsoft")] + [InlineData("/signin-google")] + [InlineData("/signin-oidc")] + public async Task SigninCallbackPaths_AreExcluded(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var middleware = new OnboardingMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + context.User = AuthenticatedUser; + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: $"'{path}' should be excluded by the /signin- prefix"); + } + + [Theory] + [InlineData("/ACME/Overview")] + [InlineData("/User/Alice")] + [InlineData("/")] + public async Task NonExcludedPaths_AttemptOnboardingCheck(string path) + { + RequestDelegate next = _ => Task.CompletedTask; + + var middleware = new OnboardingMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + context.User = AuthenticatedUser; + + // Non-excluded paths with authenticated user will attempt to resolve + // PortalApplication from DI. Since RequestServices isn't set up, this throws. + var act = () => middleware.InvokeAsync(context); + await act.Should().ThrowAsync( + because: "non-excluded paths should attempt onboarding check via PortalApplication"); + } + + [Theory] + [InlineData("/_FRAMEWORK/blazor.js")] + [InlineData("/LOGIN")] + [InlineData("/STATIC/img.png")] + public async Task ExcludedPrefixes_AreCaseInsensitive(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var middleware = new OnboardingMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + context.User = AuthenticatedUser; + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: "exclusion should be case-insensitive"); + } + + [Theory] + [InlineData("/ACME/Overview")] + [InlineData("/User/Alice")] + [InlineData("/")] + public async Task UnauthenticatedUser_SkipsEntireCheck(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var middleware = new OnboardingMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + // No user set — unauthenticated + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue( + because: "unauthenticated users should skip the entire onboarding check"); + } +} diff --git a/test/Memex.Portal.Shared.Test/VirtualUserMiddlewareExclusionTest.cs b/test/Memex.Portal.Shared.Test/VirtualUserMiddlewareExclusionTest.cs new file mode 100644 index 000000000..9b66f0314 --- /dev/null +++ b/test/Memex.Portal.Shared.Test/VirtualUserMiddlewareExclusionTest.cs @@ -0,0 +1,103 @@ +using System; +using System.Threading.Tasks; +using FluentAssertions; +using Memex.Portal.Shared.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging.Abstractions; +using Xunit; + +namespace Memex.Portal.Shared.Test; + +public class VirtualUserMiddlewareExclusionTest +{ + [Theory] + [InlineData("/_framework/blazor.web.js")] + [InlineData("/_content/MeshWeaver.Blazor/css/app.css")] + [InlineData("/_blazor/negotiate")] + [InlineData("/static/images/logo.png")] + [InlineData("/favicon.ico")] + [InlineData("/mcp")] + public async Task ExcludedPrefixes_SkipVirtualUserAssignment(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var middleware = new VirtualUserMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: $"'{path}' should be excluded and pass through to next"); + } + + [Theory] + [InlineData("/ACME/Overview")] + [InlineData("/User/Alice")] + [InlineData("/")] + public async Task NonExcludedPaths_AttemptVirtualUserAssignment(string path) + { + RequestDelegate next = _ => Task.CompletedTask; + + var middleware = new VirtualUserMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + + // Non-excluded paths will attempt to resolve PortalApplication from DI. + // Since RequestServices isn't set up, this throws. + var act = () => middleware.InvokeAsync(context); + await act.Should().ThrowAsync( + because: "non-excluded paths should attempt virtual user assignment via PortalApplication"); + } + + [Theory] + [InlineData("/_FRAMEWORK/blazor.web.js")] + [InlineData("/STATIC/image.png")] + [InlineData("/FAVICON.ICO")] + public async Task ExcludedPrefixes_AreCaseInsensitive(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var middleware = new VirtualUserMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: "exclusion should be case-insensitive"); + } + + [Theory] + [InlineData("/mcp")] + [InlineData("/mcp/tools")] + public async Task McpPath_StillExcluded(string path) + { + var nextCalled = false; + RequestDelegate next = _ => + { + nextCalled = true; + return Task.CompletedTask; + }; + + var middleware = new VirtualUserMiddleware(next, NullLogger.Instance); + + var context = new DefaultHttpContext(); + context.Request.Path = path; + + await middleware.InvokeAsync(context); + + nextCalled.Should().BeTrue(because: "MCP paths should remain excluded after refactor"); + } +} diff --git a/test/MeshWeaver.Security.Test/AccessControlPipelineTest.cs b/test/MeshWeaver.Security.Test/AccessControlPipelineTest.cs index 96533f85a..8bb393f02 100644 --- a/test/MeshWeaver.Security.Test/AccessControlPipelineTest.cs +++ b/test/MeshWeaver.Security.Test/AccessControlPipelineTest.cs @@ -264,3 +264,159 @@ public async Task Admin_HasReadOnOrganization_WithoutClaimBasedRoles() } } } + +/// +/// Tests that the User hub grants read access to authenticated users via HubPermissionRuleSet. +/// Reproduces deployed test environment error: +/// "Access denied: user 'sglauser@systemorph.com' lacks Read permission on 'User'" +/// The fix: WithUserNodePublicRead() must register AddHubPermissionRule (not just AddAccessRule). +/// +public class UserHubAccessTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => base.ConfigureMesh(builder) + .AddGraph() + .AddSampleUsers(); + + [Fact(Timeout = 10000)] + public async Task AuthenticatedUser_CanReadUserHub() + { + // Simulate an unprivileged authenticated user (no Admin role, no explicit access assignments) + var accessService = Mesh.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext { ObjectId = "unprivileged@example.com", Name = "Unprivileged User" }); + + var response = await Mesh.AwaitResponse( + new GetDataRequest(new UnifiedReference("data:")), + o => o.WithTarget(new Address("User")), + TestContext.Current.CancellationToken); + + // Should not be blocked by AccessControlPipeline + response.Message.Error.Should().NotContain("Access denied", + "authenticated user should have Read access to User hub via HubPermissionRuleSet"); + } + + [Fact(Timeout = 10000)] + public async Task AnonymousUser_CannotReadUserHub() + { + // Anonymous (empty userId) should be denied + var accessService = Mesh.ServiceProvider.GetRequiredService(); + accessService.SetCircuitContext(new AccessContext { ObjectId = "", Name = "" }); + + var ex = await Assert.ThrowsAnyAsync(async () => + await Mesh.AwaitResponse( + new GetDataRequest(new UnifiedReference("data:")), + o => o.WithTarget(new Address("User")), + TestContext.Current.CancellationToken)); + + ex.InnerException.Should().BeOfType(); + ex.InnerException!.Message.Should().Contain("Access denied"); + } +} + +/// +/// Tests the self-scope fallback in SecurityService: a user always has Admin +/// permissions on their own User/{userId} scope and its children, without +/// needing explicit AccessAssignment nodes. +/// +public class UserSelfScopeAccessTest(ITestOutputHelper output) : MonolithMeshTestBase(output) +{ + protected override MeshBuilder ConfigureMesh(MeshBuilder builder) + => ConfigureMeshBase(builder); // No PublicAdminAccess — pure RLS + + [Fact(Timeout = 10000)] + public async Task UserAccessingOwnScope_ReturnsAdmin() + { + var securityService = Mesh.ServiceProvider.GetRequiredService(); + + var permissions = await securityService.GetEffectivePermissionsAsync( + "User/alice", "alice", TestContext.Current.CancellationToken); + + permissions.Should().HaveFlag(Permission.Read); + permissions.Should().HaveFlag(Permission.Create); + permissions.Should().HaveFlag(Permission.Update); + permissions.Should().HaveFlag(Permission.Delete); + } + + [Fact(Timeout = 10000)] + public async Task UserAccessingOwnChild_ReturnsAdmin() + { + var securityService = Mesh.ServiceProvider.GetRequiredService(); + + var permissions = await securityService.GetEffectivePermissionsAsync( + "User/bob/_Thread/t1", "bob", TestContext.Current.CancellationToken); + + permissions.Should().HaveFlag(Permission.Read); + permissions.Should().HaveFlag(Permission.Create); + permissions.Should().HaveFlag(Permission.Update); + permissions.Should().HaveFlag(Permission.Delete); + } + + [Fact(Timeout = 10000)] + public async Task AnonymousAccessingUserScope_NoFallback() + { + var securityService = Mesh.ServiceProvider.GetRequiredService(); + + var permissions = await securityService.GetEffectivePermissionsAsync( + "User/alice", WellKnownUsers.Anonymous, TestContext.Current.CancellationToken); + + permissions.Should().Be(Permission.None, + "Anonymous should not get self-scope fallback on another user's scope"); + } + + [Fact(Timeout = 10000)] + public async Task PublicAccessingUserScope_NoFallback() + { + var securityService = Mesh.ServiceProvider.GetRequiredService(); + + var permissions = await securityService.GetEffectivePermissionsAsync( + "User/alice", WellKnownUsers.Public, TestContext.Current.CancellationToken); + + permissions.Should().Be(Permission.None, + "Public should not get self-scope fallback on another user's scope"); + } + + [Fact(Timeout = 10000)] + public async Task UserAccessingOtherUserScope_NoFallback() + { + var securityService = Mesh.ServiceProvider.GetRequiredService(); + + var permissions = await securityService.GetEffectivePermissionsAsync( + "User/alice", "bob", TestContext.Current.CancellationToken); + + permissions.Should().Be(Permission.None, + "bob should not have any permissions on alice's scope without explicit assignment"); + } + + [Fact(Timeout = 10000)] + public async Task UserWithExplicitAdmin_FallbackIsNoOp() + { + var securityService = Mesh.ServiceProvider.GetRequiredService(); + + // Give charlie explicit Admin on User/charlie + await securityService.AddUserRoleAsync( + "charlie", "Admin", "User/charlie", "system", + TestContext.Current.CancellationToken); + + var permissions = await securityService.GetEffectivePermissionsAsync( + "User/charlie", "charlie", TestContext.Current.CancellationToken); + + permissions.Should().HaveFlag(Permission.Read); + permissions.Should().HaveFlag(Permission.Create); + permissions.Should().HaveFlag(Permission.Update); + permissions.Should().HaveFlag(Permission.Delete); + } + + [Fact(Timeout = 10000)] + public async Task CaseInsensitivePath_Works() + { + var securityService = Mesh.ServiceProvider.GetRequiredService(); + + // Path uses lowercase "user" instead of "User" + var permissions = await securityService.GetEffectivePermissionsAsync( + "user/alice/child", "alice", TestContext.Current.CancellationToken); + + permissions.Should().HaveFlag(Permission.Read, + "self-scope fallback should be case-insensitive on path prefix"); + permissions.Should().HaveFlag(Permission.Create); + } +} From 5124e30fb60760b8967dbf7bf1bd9f7645133a6d Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Thu, 23 Apr 2026 11:17:57 +0200 Subject: [PATCH 13/14] remove accidentally tracked dist/ build artifacts --- .../Graph/Data/ACME/_Access/Public_Access.json | 17 ----------------- .../samples/Graph/Data/User/Admin.json | 13 ------------- .../samples/Graph/Data/User/Alice.json | 13 ------------- dist/templates/samples/Graph/Data/User/Bob.json | 13 ------------- .../Graph/Data/User/_Access/Admin_Access.json | 17 ----------------- .../Graph/Data/User/_Access/Alice_Access.json | 17 ----------------- .../Graph/Data/User/_Access/Bob_Access.json | 17 ----------------- 7 files changed, 107 deletions(-) delete mode 100644 dist/templates/samples/Graph/Data/ACME/_Access/Public_Access.json delete mode 100644 dist/templates/samples/Graph/Data/User/Admin.json delete mode 100644 dist/templates/samples/Graph/Data/User/Alice.json delete mode 100644 dist/templates/samples/Graph/Data/User/Bob.json delete mode 100644 dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json delete mode 100644 dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json delete mode 100644 dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json diff --git a/dist/templates/samples/Graph/Data/ACME/_Access/Public_Access.json b/dist/templates/samples/Graph/Data/ACME/_Access/Public_Access.json deleted file mode 100644 index 638eac577..000000000 --- a/dist/templates/samples/Graph/Data/ACME/_Access/Public_Access.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "Public_Access", - "namespace": "ACME/_Access", - "name": "Public Access", - "icon": "/static/NodeTypeIcons/shield.svg", - "nodeType": "AccessAssignment", - "content": { - "$type": "AccessAssignment", - "accessObject": "Public", - "displayName": "Public Users", - "roles": [ - { - "role": "Viewer" - } - ] - } -} diff --git a/dist/templates/samples/Graph/Data/User/Admin.json b/dist/templates/samples/Graph/Data/User/Admin.json deleted file mode 100644 index 198b4aa02..000000000 --- a/dist/templates/samples/Graph/Data/User/Admin.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "Admin", - "namespace": "User", - "name": "Admin", - "nodeType": "User", - "icon": "/static/NodeTypeIcons/person.svg", - "isPersistent": true, - "content": { - "$type": "User", - "email": "admin@example.com", - "bio": "Default administrator account." - } -} diff --git a/dist/templates/samples/Graph/Data/User/Alice.json b/dist/templates/samples/Graph/Data/User/Alice.json deleted file mode 100644 index 941459f5b..000000000 --- a/dist/templates/samples/Graph/Data/User/Alice.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "Alice", - "namespace": "User", - "name": "Alice Chen", - "nodeType": "User", - "icon": "/static/NodeTypeIcons/person.svg", - "isPersistent": true, - "content": { - "$type": "User", - "email": "alice.chen@meshweaver.io", - "bio": "Software engineer and project contributor." - } -} diff --git a/dist/templates/samples/Graph/Data/User/Bob.json b/dist/templates/samples/Graph/Data/User/Bob.json deleted file mode 100644 index 30b66de78..000000000 --- a/dist/templates/samples/Graph/Data/User/Bob.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "Bob", - "namespace": "User", - "name": "Bob Smith", - "nodeType": "User", - "icon": "/static/NodeTypeIcons/person.svg", - "isPersistent": true, - "content": { - "$type": "User", - "email": "bob.smith@meshweaver.io", - "bio": "Software engineer and project contributor." - } -} diff --git a/dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json b/dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json deleted file mode 100644 index 15e5ad803..000000000 --- a/dist/templates/samples/Graph/Data/User/_Access/Admin_Access.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "Admin_Access", - "namespace": "User/_Access", - "name": "Admin Access", - "icon": "/static/NodeTypeIcons/shield.svg", - "nodeType": "AccessAssignment", - "content": { - "$type": "AccessAssignment", - "accessObject": "Admin", - "displayName": "Admin", - "roles": [ - { - "role": "Admin" - } - ] - } -} diff --git a/dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json b/dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json deleted file mode 100644 index 12d4cb655..000000000 --- a/dist/templates/samples/Graph/Data/User/_Access/Alice_Access.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "Alice_Access", - "namespace": "User/_Access", - "name": "Alice Access", - "icon": "/static/NodeTypeIcons/shield.svg", - "nodeType": "AccessAssignment", - "content": { - "$type": "AccessAssignment", - "accessObject": "Alice", - "displayName": "Alice Chen", - "roles": [ - { - "role": "Admin" - } - ] - } -} diff --git a/dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json b/dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json deleted file mode 100644 index 25443b23e..000000000 --- a/dist/templates/samples/Graph/Data/User/_Access/Bob_Access.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "Bob_Access", - "namespace": "User/_Access", - "name": "Bob Access", - "icon": "/static/NodeTypeIcons/shield.svg", - "nodeType": "AccessAssignment", - "content": { - "$type": "AccessAssignment", - "accessObject": "Bob", - "displayName": "Bob Smith", - "roles": [ - { - "role": "Admin" - } - ] - } -} From 8f698ac95625c73f9590f0d3d951b77ff721e712 Mon Sep 17 00:00:00 2001 From: Samuel Glauser Date: Mon, 27 Apr 2026 14:31:21 +0200 Subject: [PATCH 14/14] Fixed unit test --- .../UserNodeTypePermissionTest.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs b/test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs index ad65ac370..237629f3d 100644 --- a/test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs +++ b/test/MeshWeaver.Graph.Test/UserNodeTypePermissionTest.cs @@ -15,6 +15,7 @@ private static MessageHubConfiguration BuildUserHubConfig() { var config = new MessageHubConfiguration(null, new Address("User", "Alice")); var meshNode = UserNodeType.CreateMeshNode(); + Assert.NotNull(meshNode.HubConfiguration); return meshNode.HubConfiguration(config); } @@ -74,7 +75,7 @@ public async Task AuthenticatedUser_CanReadDirectUserNode() // Path = "User/Alice" (derived from ns/id) var context = ReadContext("Alice", "User"); - var result = await accessRule.HasAccessAsync(context, "bob"); + var result = await accessRule.HasAccessAsync(context, "bob", TestContext.Current.CancellationToken); result.Should().BeTrue("any authenticated user can read a direct User node"); } @@ -87,10 +88,10 @@ public async Task UnauthenticatedUser_CannotReadDirectUserNode() var context = ReadContext("Alice", "User"); - var resultNull = await accessRule.HasAccessAsync(context, null); + var resultNull = await accessRule.HasAccessAsync(context, null, TestContext.Current.CancellationToken); resultNull.Should().BeFalse("unauthenticated user (null) should be denied"); - var resultEmpty = await accessRule.HasAccessAsync(context, ""); + var resultEmpty = await accessRule.HasAccessAsync(context, "", TestContext.Current.CancellationToken); resultEmpty.Should().BeFalse("unauthenticated user (empty) should be denied"); } @@ -104,7 +105,7 @@ public async Task AuthenticatedUser_CannotReadChildNode() // Path = "User/Alice/thread1" (child node) var context = ReadContext("thread1", "User/Alice"); - var result = await accessRule.HasAccessAsync(context, "bob"); + var result = await accessRule.HasAccessAsync(context, "bob", TestContext.Current.CancellationToken); result.Should().BeFalse("child nodes (threads, activities) should not be publicly readable"); } @@ -117,7 +118,7 @@ public async Task UserCanEditOwnNode() var context = UpdateContext("Alice", "User"); - var result = await accessRule.HasAccessAsync(context, "Alice"); + var result = await accessRule.HasAccessAsync(context, "Alice", TestContext.Current.CancellationToken); result.Should().BeTrue("users should be able to edit their own node"); } @@ -130,7 +131,7 @@ public async Task UserCannotEditOtherUserNode() var context = UpdateContext("Alice", "User"); - var result = await accessRule.HasAccessAsync(context, "Bob"); + var result = await accessRule.HasAccessAsync(context, "Bob", TestContext.Current.CancellationToken); result.Should().BeFalse("users should not be able to edit other users' nodes"); }