@goable-io/sdk 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -118,6 +118,11 @@ export interface paths {
118
118
  /** @description L2a probabilistic ensemble (Pro+) */
119
119
  ensemble?: boolean;
120
120
  members?: number;
121
+ /**
122
+ * @description Skill-conditioned scoring (Pro+).
123
+ * @enum {string}
124
+ */
125
+ rider_skill_level?: "beginner" | "intermediate" | "expert";
121
126
  };
122
127
  };
123
128
  };
@@ -131,7 +136,7 @@ export interface paths {
131
136
  "application/json": components["schemas"]["ScoreResponse"];
132
137
  };
133
138
  };
134
- /** @description Plan upgrade required (ensemble on Free/Starter) */
139
+ /** @description Plan upgrade required (ensemble or rider_skill_level on Free/Starter) */
135
140
  402: {
136
141
  headers: {
137
142
  [name: string]: unknown;
@@ -296,7 +301,10 @@ export interface paths {
296
301
  };
297
302
  get?: never;
298
303
  put?: never;
299
- /** Historical climatology scoring (Pro+) */
304
+ /**
305
+ * Historical climatology scoring (Pro+)
306
+ * @description Percentiles + exceedance + verdict frequency over ERA5 reanalysis. Each entry carries a historical-mode ConfidenceDetail block (see components.schemas.ConfidenceDetailHistorical).
307
+ */
300
308
  post: {
301
309
  parameters: {
302
310
  query?: never;
@@ -327,7 +335,7 @@ export interface paths {
327
335
  };
328
336
  };
329
337
  responses: {
330
- /** @description Percentiles + exceedance + verdict frequency */
338
+ /** @description Percentiles + exceedance + verdict frequency (per-entry confidenceDetail: historical) */
331
339
  200: {
332
340
  headers: {
333
341
  [name: string]: unknown;
@@ -799,7 +807,10 @@ export interface paths {
799
807
  };
800
808
  get?: never;
801
809
  put?: never;
802
- /** Climate-decadal activity viability projection (Scale) */
810
+ /**
811
+ * Climate-decadal activity viability projection (Scale)
812
+ * @description Per-decade projection distributions. Each entry carries a climate-mode ConfidenceDetail block (see components.schemas.ConfidenceDetailClimate).
813
+ */
803
814
  post: {
804
815
  parameters: {
805
816
  query?: never;
@@ -823,7 +834,7 @@ export interface paths {
823
834
  };
824
835
  };
825
836
  responses: {
826
- /** @description Per-decade projection distributions */
837
+ /** @description Per-decade projection distributions (per-entry confidenceDetail: climate) */
827
838
  200: {
828
839
  headers: {
829
840
  [name: string]: unknown;
@@ -869,7 +880,10 @@ export interface paths {
869
880
  };
870
881
  get?: never;
871
882
  put?: never;
872
- /** Parametric underwriting quote (Scale) */
883
+ /**
884
+ * Parametric underwriting quote (Scale)
885
+ * @description Multi-currency `expectedPremium.byCurrency` — a mixed-currency portfolio returns per-currency stats with no FX conversion. `policy.spot.tier` / `policy.portfolio[i].tier` echo the resolved sub-spot tier (1/2/3) or null when no sub-spot covers the point; `tierSource` marks whether it came from the catalog YAML or L11's data-driven classifier.
886
+ */
873
887
  post: {
874
888
  parameters: {
875
889
  query?: never;
@@ -881,43 +895,64 @@ export interface paths {
881
895
  content: {
882
896
  "application/json": {
883
897
  spot?: {
884
- location: components["schemas"]["GeoPoint"];
898
+ point: components["schemas"]["GeoPoint"];
885
899
  activity: string;
886
900
  spotId?: string;
901
+ payout: {
902
+ amount: number;
903
+ /** @enum {string} */
904
+ currency: "EUR" | "USD" | "GBP" | "CHF";
905
+ };
887
906
  };
888
907
  portfolio?: {
889
- location: components["schemas"]["GeoPoint"];
908
+ point: components["schemas"]["GeoPoint"];
890
909
  activity: string;
891
910
  spotId?: string;
911
+ payout: {
912
+ amount: number;
913
+ /** @enum {string} */
914
+ currency: "EUR" | "USD" | "GBP" | "CHF";
915
+ };
892
916
  }[];
893
917
  coverageWindow: {
894
918
  monthFrom: number;
895
919
  dayFrom: number;
896
920
  monthTo: number;
897
921
  dayTo: number;
898
- } & {
899
- [key: string]: unknown;
900
922
  };
901
- payout?: {
902
- amount: number;
923
+ trigger: {
903
924
  /** @enum {string} */
904
- currency: "EUR" | "USD" | "GBP" | "CHF";
925
+ kind: "scoreBelow";
926
+ scoreBelow: number;
927
+ consecutiveHours?: number;
928
+ cooldownHours?: number;
929
+ maxPayoutsPerYear?: number;
930
+ } | {
931
+ /** @enum {string} */
932
+ kind: "verdictAtOrBelow";
933
+ verdict: components["schemas"]["Verdict"];
934
+ consecutiveHours?: number;
935
+ cooldownHours?: number;
936
+ maxPayoutsPerYear?: number;
905
937
  };
906
- } & {
907
- [key: string]: unknown;
938
+ historicalYearsRange?: {
939
+ from: number;
940
+ to: number;
941
+ };
942
+ loadingFactor?: number;
943
+ calibrationConfidenceMin?: number;
944
+ forceIssue?: boolean;
908
945
  };
909
946
  };
910
947
  };
911
948
  responses: {
912
- /** @description Premium + bindable policy terms */
949
+ /** @description Premium + policy echo (with per-spot tier + tierSource) + bindable quote id when policy store is wired */
913
950
  200: {
914
951
  headers: {
915
952
  [name: string]: unknown;
916
953
  };
917
954
  content: {
918
- "application/json": {
919
- [key: string]: unknown;
920
- };
955
+ "application/json": components["schemas"]["UnderwritingQuoteResponse"];
921
956
  };
922
957
  };
923
958
  /** @description Requires Scale plan */
@@ -929,7 +964,16 @@ export interface paths {
929
964
  "application/json": components["schemas"]["Error"];
930
965
  };
931
966
  };
932
- /** @description Validation error */
967
+ /** @description No profile for activity */
968
+ 404: {
969
+ headers: {
970
+ [name: string]: unknown;
971
+ };
972
+ content: {
973
+ "application/json": components["schemas"]["Error"];
974
+ };
975
+ };
976
+ /** @description Validation error / low confidence / invalid trigger */
933
977
  422: {
934
978
  headers: {
935
979
  [name: string]: unknown;
@@ -938,6 +982,15 @@ export interface paths {
938
982
  "application/json": components["schemas"]["Error"];
939
983
  };
940
984
  };
985
+ /** @description HistoricalProvider not configured */
986
+ 503: {
987
+ headers: {
988
+ [name: string]: unknown;
989
+ };
990
+ content: {
991
+ "application/json": components["schemas"]["Error"];
992
+ };
993
+ };
941
994
  };
942
995
  };
943
996
  delete?: never;
@@ -946,48 +999,35 @@ export interface paths {
946
999
  patch?: never;
947
1000
  trace?: never;
948
1001
  };
949
- "/v1/underwriting/bind": {
1002
+ "/v1/underwriting/quote/{id}": {
950
1003
  parameters: {
951
1004
  query?: never;
952
1005
  header?: never;
953
1006
  path?: never;
954
1007
  cookie?: never;
955
1008
  };
956
- get?: never;
957
- put?: never;
958
1009
  /**
959
- * Bind a parametric policy (Scale)
960
- * @description Convert a recent /v1/underwriting/quote into a bound policy. Submit the quoteId (≤24h old); returns a policyId + immutable cohortHash anchoring the bound weather sample set.
1010
+ * Fetch a bindable quote by id (Scale)
1011
+ * @description Tenant-scoped read of a quote created via POST /v1/underwriting/quote. Returns the same body shape as the create response (with the optional `boundPolicyId` populated once the quote has been bound).
961
1012
  */
962
- post: {
1013
+ get: {
963
1014
  parameters: {
964
1015
  query?: never;
965
1016
  header?: never;
966
- path?: never;
967
- cookie?: never;
968
- };
969
- requestBody: {
970
- content: {
971
- "application/json": {
972
- quoteId: string;
973
- premiumConfirmation?: {
974
- [key: string]: unknown;
975
- };
976
- } & {
977
- [key: string]: unknown;
978
- };
1017
+ path: {
1018
+ id: string;
979
1019
  };
1020
+ cookie?: never;
980
1021
  };
1022
+ requestBody?: never;
981
1023
  responses: {
982
- /** @description Bound policy id + cohort hash + settlement schedule */
1024
+ /** @description Quote record (may include boundPolicyId when already bound) */
983
1025
  200: {
984
1026
  headers: {
985
1027
  [name: string]: unknown;
986
1028
  };
987
1029
  content: {
988
- "application/json": {
989
- [key: string]: unknown;
990
- };
1030
+ "application/json": components["schemas"]["UnderwritingQuoteResponse"];
991
1031
  };
992
1032
  };
993
1033
  /** @description Requires Scale plan */
@@ -999,7 +1039,7 @@ export interface paths {
999
1039
  "application/json": components["schemas"]["Error"];
1000
1040
  };
1001
1041
  };
1002
- /** @description Quote expired or not found */
1042
+ /** @description Quote not found for this tenant */
1003
1043
  404: {
1004
1044
  headers: {
1005
1045
  [name: string]: unknown;
@@ -1008,8 +1048,8 @@ export interface paths {
1008
1048
  "application/json": components["schemas"]["Error"];
1009
1049
  };
1010
1050
  };
1011
- /** @description Validation error */
1012
- 422: {
1051
+ /** @description Quote persistence not configured */
1052
+ 503: {
1013
1053
  headers: {
1014
1054
  [name: string]: unknown;
1015
1055
  };
@@ -1019,13 +1059,15 @@ export interface paths {
1019
1059
  };
1020
1060
  };
1021
1061
  };
1062
+ put?: never;
1063
+ post?: never;
1022
1064
  delete?: never;
1023
1065
  options?: never;
1024
1066
  head?: never;
1025
1067
  patch?: never;
1026
1068
  trace?: never;
1027
1069
  };
1028
- "/v1/underwriting/evaluate": {
1070
+ "/v1/underwriting/policy/bind": {
1029
1071
  parameters: {
1030
1072
  query?: never;
1031
1073
  header?: never;
@@ -1035,8 +1077,8 @@ export interface paths {
1035
1077
  get?: never;
1036
1078
  put?: never;
1037
1079
  /**
1038
- * Read-only payout projection for a bound policy (Scale)
1039
- * @description Returns the current accrued shortfall + projected payout for a bound policy. Does NOT settle settlement runs automatically on a cron at policy expiry.
1080
+ * Bind a parametric policy (Scale)
1081
+ * @description Convert a bindable quote (≤24h old) into a bound policy for a specific coverage year. Returns the serialised policy + the quoteId + optional `driftAdvisories` — a soft warning surfaced when the resolved cell has an open watch-level L9 drift event. A warning/critical drift event at bind time REFUSES the bind with 422 DRIFT_ACTIVE (see the 422 response). Fires the `underwriting.policy.bound` webhook on success.
1040
1082
  */
1041
1083
  post: {
1042
1084
  parameters: {
@@ -1048,19 +1090,36 @@ export interface paths {
1048
1090
  requestBody: {
1049
1091
  content: {
1050
1092
  "application/json": {
1051
- policyId: string;
1093
+ /** Format: uuid */
1094
+ quoteId: string;
1095
+ coverageYear: number;
1096
+ /** @enum {string} */
1097
+ premiumCollection: "external" | "stripe" | "invoice_due";
1098
+ premiumPaid?: number;
1052
1099
  };
1053
1100
  };
1054
1101
  };
1055
1102
  responses: {
1056
- /** @description Accrued shortfall + projected payout per currency */
1057
- 200: {
1103
+ /** @description Policy bound */
1104
+ 201: {
1058
1105
  headers: {
1059
1106
  [name: string]: unknown;
1060
1107
  };
1061
1108
  content: {
1062
1109
  "application/json": {
1063
- [key: string]: unknown;
1110
+ policy: components["schemas"]["SerialisedPolicy"];
1111
+ /** Format: uuid */
1112
+ quoteId: string;
1113
+ /** @description Soft warnings for cells with an open watch-level L9 drift event. Present only when non-empty. */
1114
+ driftAdvisories?: {
1115
+ spotIndex: number;
1116
+ activity: string;
1117
+ subSpotSlug: string;
1118
+ /** @enum {string} */
1119
+ severity: "watch";
1120
+ /** Format: date-time */
1121
+ since: string;
1122
+ }[];
1064
1123
  };
1065
1124
  };
1066
1125
  };
@@ -1073,7 +1132,7 @@ export interface paths {
1073
1132
  "application/json": components["schemas"]["Error"];
1074
1133
  };
1075
1134
  };
1076
- /** @description Policy not found */
1135
+ /** @description Quote not found for this tenant */
1077
1136
  404: {
1078
1137
  headers: {
1079
1138
  [name: string]: unknown;
@@ -1082,7 +1141,16 @@ export interface paths {
1082
1141
  "application/json": components["schemas"]["Error"];
1083
1142
  };
1084
1143
  };
1085
- /** @description Validation error */
1144
+ /** @description Quote already bound to another policy */
1145
+ 409: {
1146
+ headers: {
1147
+ [name: string]: unknown;
1148
+ };
1149
+ content: {
1150
+ "application/json": components["schemas"]["Error"];
1151
+ };
1152
+ };
1153
+ /** @description Validation error / quote expired / quote not issuable / catalog drift / DRIFT_ACTIVE (open warning or critical drift event on resolved cell — `detail.openDriftEvents` lists each blocking cell) */
1086
1154
  422: {
1087
1155
  headers: {
1088
1156
  [name: string]: unknown;
@@ -1091,6 +1159,15 @@ export interface paths {
1091
1159
  "application/json": components["schemas"]["Error"];
1092
1160
  };
1093
1161
  };
1162
+ /** @description Policy persistence not configured */
1163
+ 503: {
1164
+ headers: {
1165
+ [name: string]: unknown;
1166
+ };
1167
+ content: {
1168
+ "application/json": components["schemas"]["Error"];
1169
+ };
1170
+ };
1094
1171
  };
1095
1172
  };
1096
1173
  delete?: never;
@@ -1099,54 +1176,44 @@ export interface paths {
1099
1176
  patch?: never;
1100
1177
  trace?: never;
1101
1178
  };
1102
- "/v1/score/{sessionId}/outcome": {
1179
+ "/v1/underwriting/policy": {
1103
1180
  parameters: {
1104
1181
  query?: never;
1105
1182
  header?: never;
1106
1183
  path?: never;
1107
1184
  cookie?: never;
1108
1185
  };
1109
- get?: never;
1110
- put?: never;
1111
1186
  /**
1112
- * Report observed outcome for a scored session
1113
- * @description Close the calibration loop. Submit the actual outcome (ran/cancelled/no_show/rescheduled/note) of a /v1/score session. The calibration pipeline + forecast verification + drift monitor consume these. Requires the `outcomes:write` scope (live keys carry it by default; test keys don't).
1187
+ * List bound policies for the caller's tenant (Scale)
1188
+ * @description Paginated list of every bound policy owned by the calling tenant. Ordered by boundAt DESC.
1114
1189
  */
1115
- post: {
1190
+ get: {
1116
1191
  parameters: {
1117
- query?: never;
1118
- header?: never;
1119
- path: {
1120
- /** @description Session UUID returned in the /v1/score response metadata. */
1121
- sessionId: string;
1192
+ query?: {
1193
+ status?: "bound" | "triggered" | "settled" | "expired";
1194
+ coverageYear?: number;
1195
+ limit?: number;
1196
+ cursor?: string;
1122
1197
  };
1198
+ header?: never;
1199
+ path?: never;
1123
1200
  cookie?: never;
1124
1201
  };
1125
- requestBody: {
1126
- content: {
1127
- "application/json": {
1128
- /** @enum {string} */
1129
- outcome_type: "ran" | "cancelled" | "rescheduled" | "no_show" | "note";
1130
- detail?: {
1131
- [key: string]: unknown;
1132
- };
1133
- };
1134
- };
1135
- };
1202
+ requestBody?: never;
1136
1203
  responses: {
1137
- /** @description Accepted (queued for the next calibration batch) */
1138
- 202: {
1204
+ /** @description Bound policies for this tenant */
1205
+ 200: {
1139
1206
  headers: {
1140
1207
  [name: string]: unknown;
1141
1208
  };
1142
1209
  content: {
1143
1210
  "application/json": {
1144
- [key: string]: unknown;
1211
+ policies: components["schemas"]["SerialisedPolicy"][];
1145
1212
  };
1146
1213
  };
1147
1214
  };
1148
- /** @description Missing scope: outcomes:write */
1149
- 403: {
1215
+ /** @description Requires Scale plan */
1216
+ 402: {
1150
1217
  headers: {
1151
1218
  [name: string]: unknown;
1152
1219
  };
@@ -1154,8 +1221,8 @@ export interface paths {
1154
1221
  "application/json": components["schemas"]["Error"];
1155
1222
  };
1156
1223
  };
1157
- /** @description Session not found */
1158
- 404: {
1224
+ /** @description Validation error */
1225
+ 422: {
1159
1226
  headers: {
1160
1227
  [name: string]: unknown;
1161
1228
  };
@@ -1163,8 +1230,8 @@ export interface paths {
1163
1230
  "application/json": components["schemas"]["Error"];
1164
1231
  };
1165
1232
  };
1166
- /** @description Validation error */
1167
- 422: {
1233
+ /** @description Policy persistence not configured */
1234
+ 503: {
1168
1235
  headers: {
1169
1236
  [name: string]: unknown;
1170
1237
  };
@@ -1174,56 +1241,58 @@ export interface paths {
1174
1241
  };
1175
1242
  };
1176
1243
  };
1244
+ put?: never;
1245
+ post?: never;
1177
1246
  delete?: never;
1178
1247
  options?: never;
1179
1248
  head?: never;
1180
1249
  patch?: never;
1181
1250
  trace?: never;
1182
1251
  };
1183
- "/v1/score/difficulty": {
1252
+ "/v1/underwriting/policy/{policyId}": {
1184
1253
  parameters: {
1185
1254
  query?: never;
1186
1255
  header?: never;
1187
1256
  path?: never;
1188
1257
  cookie?: never;
1189
1258
  };
1190
- get?: never;
1191
- put?: never;
1192
1259
  /**
1193
- * Skill-conditioned scoring
1194
- * @description Same scoring engine, but conditioned on a rider/operator skill level. Returns the score curve as a function of skill so a booking flow can branch ("good for beginners" vs "experts only").
1260
+ * Fetch a single policy by id (Scale)
1261
+ * @description Read-only lookup. Cross-tenant policies return 404.
1195
1262
  */
1196
- post: {
1263
+ get: {
1197
1264
  parameters: {
1198
1265
  query?: never;
1199
1266
  header?: never;
1200
- path?: never;
1201
- cookie?: never;
1202
- };
1203
- requestBody: {
1204
- content: {
1205
- "application/json": {
1206
- activity: string;
1207
- location: components["schemas"]["GeoPoint"];
1208
- window?: components["schemas"]["TimeWindow"];
1209
- /** @description Skill points (0-1) to score. Defaults to 5 quantile points. */
1210
- riderSkillLevels?: number[];
1211
- };
1267
+ path: {
1268
+ policyId: string;
1212
1269
  };
1270
+ cookie?: never;
1213
1271
  };
1272
+ requestBody?: never;
1214
1273
  responses: {
1215
- /** @description Score per skill level + difficulty band */
1274
+ /** @description Policy record + payout events */
1216
1275
  200: {
1217
1276
  headers: {
1218
1277
  [name: string]: unknown;
1219
1278
  };
1220
1279
  content: {
1221
1280
  "application/json": {
1222
- [key: string]: unknown;
1281
+ policy: components["schemas"]["SerialisedPolicy"];
1282
+ events: components["schemas"]["SerialisedPayoutEvent"][];
1223
1283
  };
1224
1284
  };
1225
1285
  };
1226
- /** @description No profile for activity */
1286
+ /** @description Requires Scale plan */
1287
+ 402: {
1288
+ headers: {
1289
+ [name: string]: unknown;
1290
+ };
1291
+ content: {
1292
+ "application/json": components["schemas"]["Error"];
1293
+ };
1294
+ };
1295
+ /** @description Policy not found */
1227
1296
  404: {
1228
1297
  headers: {
1229
1298
  [name: string]: unknown;
@@ -1232,8 +1301,8 @@ export interface paths {
1232
1301
  "application/json": components["schemas"]["Error"];
1233
1302
  };
1234
1303
  };
1235
- /** @description Validation error */
1236
- 422: {
1304
+ /** @description Policy persistence not configured */
1305
+ 503: {
1237
1306
  headers: {
1238
1307
  [name: string]: unknown;
1239
1308
  };
@@ -1243,13 +1312,15 @@ export interface paths {
1243
1312
  };
1244
1313
  };
1245
1314
  };
1315
+ put?: never;
1316
+ post?: never;
1246
1317
  delete?: never;
1247
1318
  options?: never;
1248
1319
  head?: never;
1249
1320
  patch?: never;
1250
1321
  trace?: never;
1251
1322
  };
1252
- "/v1/recommend-spot": {
1323
+ "/v1/underwriting/policy/{policyId}/evaluate": {
1253
1324
  parameters: {
1254
1325
  query?: never;
1255
1326
  header?: never;
@@ -1259,78 +1330,36 @@ export interface paths {
1259
1330
  get?: never;
1260
1331
  put?: never;
1261
1332
  /**
1262
- * Spot recommender inverse query (L10)
1263
- * @description Given (activity, region center, radius, window) top-K ranked sub-spots in the catalog. Composition of L1-L3 scoring + L4.6 confidence + L6 personal blend (Pro+, when pseudonym supplied). Plan caps: radius 25/50/200/1000 km, topK 5/10/20/50 across Free / Starter / Pro / Scale. Personalization Pro+ only. Hard-gated candidates (lightning ≥ 0.85, AQI hazardous) are dropped from results; `allGated=true` distinguishes 'all in-radius spots were unsafe' from 'no spots in radius at all'.
1333
+ * Re-evaluate a bound policy against historical replay (Scale)
1334
+ * @description Runs the trigger walk against the historical archive for the policy's coverage year and inserts any newly detected payout events. No request body. Fires the `underwriting.policy.triggered` webhook the first time new events are inserted.
1264
1335
  */
1265
1336
  post: {
1266
1337
  parameters: {
1267
1338
  query?: never;
1268
1339
  header?: never;
1269
- path?: never;
1270
- cookie?: never;
1271
- };
1272
- requestBody: {
1273
- content: {
1274
- "application/json": {
1275
- activity: string;
1276
- regionCenter: components["schemas"]["GeoPoint"];
1277
- radiusKm: number;
1278
- topK: number;
1279
- window?: components["schemas"]["TimeWindow"];
1280
- /** @description Optional booking-platform-side pseudonym. When present, Pro+ tenants get personalization via the L6 cold-start blend (cap 0.5 weight). */
1281
- userPseudonym?: string;
1282
- };
1340
+ path: {
1341
+ policyId: string;
1283
1342
  };
1343
+ cookie?: never;
1284
1344
  };
1345
+ requestBody?: never;
1285
1346
  responses: {
1286
- /** @description Ranked top-K sub-spots + observability metadata. The optional `coverage` field appears only on empty results from a catalog gap (not from hard-gating). */
1347
+ /** @description Policy + payout events + counts of newly inserted / skipped */
1287
1348
  200: {
1288
1349
  headers: {
1289
1350
  [name: string]: unknown;
1290
1351
  };
1291
1352
  content: {
1292
1353
  "application/json": {
1293
- results?: {
1294
- spotSlug?: string;
1295
- name?: string;
1296
- location?: components["schemas"]["GeoPoint"];
1297
- distanceKm?: number;
1298
- score?: number;
1299
- effectiveScore?: number;
1300
- verdict?: string;
1301
- personalScore?: number | null;
1302
- personalWeight?: number;
1303
- rank?: number;
1304
- }[];
1305
- allGated?: boolean;
1306
- totalCandidates?: number;
1307
- rankedCandidates?: number;
1308
- effectiveRadiusKm?: number;
1309
- effectiveTopK?: number;
1310
- personalizationApplied?: boolean;
1311
- latencyMs?: number;
1312
- coverage?: {
1313
- /** @enum {string} */
1314
- status: "no_subspots_in_radius";
1315
- nearestSubSpot: {
1316
- slug: string;
1317
- name: string;
1318
- distanceKm: number;
1319
- };
1320
- /** @enum {string} */
1321
- suggestedAction: "expand_radius";
1322
- suggestedRadiusKm: number;
1323
- } | {
1324
- /** @enum {string} */
1325
- status: "no_subspots_for_activity";
1326
- /** @enum {string} */
1327
- suggestedAction: "request_coverage";
1328
- };
1354
+ policy: components["schemas"]["SerialisedPolicy"];
1355
+ events: components["schemas"]["SerialisedPayoutEvent"][];
1356
+ inserted: number;
1357
+ skipped: number;
1329
1358
  };
1330
1359
  };
1331
1360
  };
1332
- /** @description Missing/invalid bearer token */
1333
- 401: {
1361
+ /** @description Requires Scale plan */
1362
+ 402: {
1334
1363
  headers: {
1335
1364
  [name: string]: unknown;
1336
1365
  };
@@ -1338,8 +1367,8 @@ export interface paths {
1338
1367
  "application/json": components["schemas"]["Error"];
1339
1368
  };
1340
1369
  };
1341
- /** @description Plan limit exceeded (radius or topK above plan cap) */
1342
- 402: {
1370
+ /** @description Policy not found */
1371
+ 404: {
1343
1372
  headers: {
1344
1373
  [name: string]: unknown;
1345
1374
  };
@@ -1347,7 +1376,7 @@ export interface paths {
1347
1376
  "application/json": components["schemas"]["Error"];
1348
1377
  };
1349
1378
  };
1350
- /** @description Validation error or unknown activity */
1379
+ /** @description Policy in a terminal state (settled / expired) */
1351
1380
  422: {
1352
1381
  headers: {
1353
1382
  [name: string]: unknown;
@@ -1356,7 +1385,7 @@ export interface paths {
1356
1385
  "application/json": components["schemas"]["Error"];
1357
1386
  };
1358
1387
  };
1359
- /** @description Spatial resolver not wired */
1388
+ /** @description Policy persistence or HistoricalProvider not configured */
1360
1389
  503: {
1361
1390
  headers: {
1362
1391
  [name: string]: unknown;
@@ -1373,7 +1402,7 @@ export interface paths {
1373
1402
  patch?: never;
1374
1403
  trace?: never;
1375
1404
  };
1376
- "/v1/intelligence/edge-case": {
1405
+ "/v1/underwriting/policy/{policyId}/settle": {
1377
1406
  parameters: {
1378
1407
  query?: never;
1379
1408
  header?: never;
@@ -1383,43 +1412,40 @@ export interface paths {
1383
1412
  get?: never;
1384
1413
  put?: never;
1385
1414
  /**
1386
- * LLM analysis of a borderline / surprising score (L2c, Pro+)
1387
- * @description Asks the LLM to inspect a score that's near a verdict boundary or contradicts operator intuition. Returns a narrative + a structured `limiting_class` taxonomy entry.
1415
+ * Settle a bound policy (platform-ops only)
1416
+ * @description PLATFORM-OPS ONLY — requires the `platform_admin` scope (cross-tenant Goable/underwriter operation, not a policyholder self-service action). Records the settlement wire reference + freezes the payout, and fires the `underwriting.policy.settled` webhook. Normally invoked by the daily settlement cron; use manually only for out-of-band settlement.
1388
1417
  */
1389
1418
  post: {
1390
1419
  parameters: {
1391
1420
  query?: never;
1392
1421
  header?: never;
1393
- path?: never;
1422
+ path: {
1423
+ policyId: string;
1424
+ };
1394
1425
  cookie?: never;
1395
1426
  };
1396
1427
  requestBody: {
1397
1428
  content: {
1398
1429
  "application/json": {
1399
- location: components["schemas"]["GeoPoint"];
1400
- scoreResult?: components["schemas"]["ScoreResponse"];
1401
- /** Format: uuid */
1402
- session_id?: string;
1403
- /** @enum {string} */
1404
- locale?: "en" | "it";
1405
- /** @enum {string} */
1406
- model?: "claude-haiku-4-5-20251001" | "claude-sonnet-4-6";
1430
+ settlementReference: string;
1431
+ /** Format: date-time */
1432
+ settledAt?: string;
1407
1433
  };
1408
1434
  };
1409
1435
  };
1410
1436
  responses: {
1411
- /** @description Narrative + limiting_class */
1437
+ /** @description Settled policy */
1412
1438
  200: {
1413
1439
  headers: {
1414
1440
  [name: string]: unknown;
1415
1441
  };
1416
1442
  content: {
1417
1443
  "application/json": {
1418
- [key: string]: unknown;
1444
+ policy: components["schemas"]["SerialisedPolicy"];
1419
1445
  };
1420
1446
  };
1421
1447
  };
1422
- /** @description Requires Pro+ plan */
1448
+ /** @description Requires Scale plan */
1423
1449
  402: {
1424
1450
  headers: {
1425
1451
  [name: string]: unknown;
@@ -1428,6 +1454,114 @@ export interface paths {
1428
1454
  "application/json": components["schemas"]["Error"];
1429
1455
  };
1430
1456
  };
1457
+ /** @description Missing scope: platform_admin */
1458
+ 403: {
1459
+ headers: {
1460
+ [name: string]: unknown;
1461
+ };
1462
+ content: {
1463
+ "application/json": components["schemas"]["Error"];
1464
+ };
1465
+ };
1466
+ /** @description Policy not found */
1467
+ 404: {
1468
+ headers: {
1469
+ [name: string]: unknown;
1470
+ };
1471
+ content: {
1472
+ "application/json": components["schemas"]["Error"];
1473
+ };
1474
+ };
1475
+ /** @description Validation error or policy not in a settleable state */
1476
+ 422: {
1477
+ headers: {
1478
+ [name: string]: unknown;
1479
+ };
1480
+ content: {
1481
+ "application/json": components["schemas"]["Error"];
1482
+ };
1483
+ };
1484
+ /** @description Policy persistence not configured */
1485
+ 503: {
1486
+ headers: {
1487
+ [name: string]: unknown;
1488
+ };
1489
+ content: {
1490
+ "application/json": components["schemas"]["Error"];
1491
+ };
1492
+ };
1493
+ };
1494
+ };
1495
+ delete?: never;
1496
+ options?: never;
1497
+ head?: never;
1498
+ patch?: never;
1499
+ trace?: never;
1500
+ };
1501
+ "/v1/score/{sessionId}/outcome": {
1502
+ parameters: {
1503
+ query?: never;
1504
+ header?: never;
1505
+ path?: never;
1506
+ cookie?: never;
1507
+ };
1508
+ get?: never;
1509
+ put?: never;
1510
+ /**
1511
+ * Report observed outcome for a scored session
1512
+ * @description Close the calibration loop. Submit the actual outcome (ran/cancelled/no_show/rescheduled/note) of a /v1/score session. The calibration pipeline + forecast verification + drift monitor consume these. Requires the `outcomes:write` scope (live keys carry it by default; test keys don't).
1513
+ */
1514
+ post: {
1515
+ parameters: {
1516
+ query?: never;
1517
+ header?: never;
1518
+ path: {
1519
+ /** @description Session UUID returned in the /v1/score response metadata. */
1520
+ sessionId: string;
1521
+ };
1522
+ cookie?: never;
1523
+ };
1524
+ requestBody: {
1525
+ content: {
1526
+ "application/json": {
1527
+ /** @enum {string} */
1528
+ outcome_type: "ran" | "cancelled" | "rescheduled" | "no_show" | "note";
1529
+ detail?: {
1530
+ [key: string]: unknown;
1531
+ };
1532
+ };
1533
+ };
1534
+ };
1535
+ responses: {
1536
+ /** @description Accepted (queued for the next calibration batch) */
1537
+ 202: {
1538
+ headers: {
1539
+ [name: string]: unknown;
1540
+ };
1541
+ content: {
1542
+ "application/json": {
1543
+ [key: string]: unknown;
1544
+ };
1545
+ };
1546
+ };
1547
+ /** @description Missing scope: outcomes:write */
1548
+ 403: {
1549
+ headers: {
1550
+ [name: string]: unknown;
1551
+ };
1552
+ content: {
1553
+ "application/json": components["schemas"]["Error"];
1554
+ };
1555
+ };
1556
+ /** @description Session not found */
1557
+ 404: {
1558
+ headers: {
1559
+ [name: string]: unknown;
1560
+ };
1561
+ content: {
1562
+ "application/json": components["schemas"]["Error"];
1563
+ };
1564
+ };
1431
1565
  /** @description Validation error */
1432
1566
  422: {
1433
1567
  headers: {
@@ -1445,7 +1579,7 @@ export interface paths {
1445
1579
  patch?: never;
1446
1580
  trace?: never;
1447
1581
  };
1448
- "/v1/projections/portfolio": {
1582
+ "/v1/score/difficulty": {
1449
1583
  parameters: {
1450
1584
  query?: never;
1451
1585
  header?: never;
@@ -1454,7 +1588,10 @@ export interface paths {
1454
1588
  };
1455
1589
  get?: never;
1456
1590
  put?: never;
1457
- /** Climate projections across a portfolio of spots (Scale) */
1591
+ /**
1592
+ * L15 intrinsic-difficulty atlas lookup (Pro+)
1593
+ * @description Returns the per-dimension intrinsic difficulty curve δ(x) for the sub-spot the (activity, location) resolves to. Pure atlas read — no scoring, no weather fetch. 404 NO_DIFFICULTY_ATLAS when the sub-spot resolves but no atlas row exists yet (dormant cell — communicated honestly rather than synthesised).
1594
+ */
1458
1595
  post: {
1459
1596
  parameters: {
1460
1597
  query?: never;
@@ -1465,31 +1602,39 @@ export interface paths {
1465
1602
  requestBody: {
1466
1603
  content: {
1467
1604
  "application/json": {
1468
- spots: {
1469
- location: components["schemas"]["GeoPoint"];
1470
- activity: string;
1471
- spotId?: string;
1472
- }[];
1473
- scenarios: ("SSP1-2.6" | "SSP2-4.5" | "SSP3-7.0" | "SSP5-8.5")[];
1474
- horizonDecades?: string[];
1475
- /** @enum {string} */
1476
- baselineDecade?: "2020s" | "2030s";
1605
+ activity: string;
1606
+ location: components["schemas"]["GeoPoint"];
1477
1607
  };
1478
1608
  };
1479
1609
  };
1480
1610
  responses: {
1481
- /** @description Per-spot per-decade projection distributions */
1611
+ /** @description Per-dimension intrinsic difficulty curves for the resolved sub-spot */
1482
1612
  200: {
1483
1613
  headers: {
1484
1614
  [name: string]: unknown;
1485
1615
  };
1486
1616
  content: {
1487
1617
  "application/json": {
1488
- [key: string]: unknown;
1618
+ resolved: {
1619
+ /** @enum {string} */
1620
+ level: "sub-spot" | "cluster" | "region" | "base";
1621
+ slug: string;
1622
+ sub_spot_slug?: string;
1623
+ distance_to_sub_spot_m?: number;
1624
+ };
1625
+ dimensions: {
1626
+ dimension: string;
1627
+ grid: number[];
1628
+ difficulty: number[];
1629
+ discrimination_a: number;
1630
+ cohort_hash: string;
1631
+ /** Format: date-time */
1632
+ computed_at: string;
1633
+ }[];
1489
1634
  };
1490
1635
  };
1491
1636
  };
1492
- /** @description Requires Scale plan */
1637
+ /** @description Requires Pro+ plan */
1493
1638
  402: {
1494
1639
  headers: {
1495
1640
  [name: string]: unknown;
@@ -1498,6 +1643,15 @@ export interface paths {
1498
1643
  "application/json": components["schemas"]["Error"];
1499
1644
  };
1500
1645
  };
1646
+ /** @description No profile for activity, or no atlas row for the resolved sub-spot */
1647
+ 404: {
1648
+ headers: {
1649
+ [name: string]: unknown;
1650
+ };
1651
+ content: {
1652
+ "application/json": components["schemas"]["Error"];
1653
+ };
1654
+ };
1501
1655
  /** @description Validation error */
1502
1656
  422: {
1503
1657
  headers: {
@@ -1507,6 +1661,15 @@ export interface paths {
1507
1661
  "application/json": components["schemas"]["Error"];
1508
1662
  };
1509
1663
  };
1664
+ /** @description Difficulty atlas reader not wired */
1665
+ 503: {
1666
+ headers: {
1667
+ [name: string]: unknown;
1668
+ };
1669
+ content: {
1670
+ "application/json": components["schemas"]["Error"];
1671
+ };
1672
+ };
1510
1673
  };
1511
1674
  };
1512
1675
  delete?: never;
@@ -1515,7 +1678,7 @@ export interface paths {
1515
1678
  patch?: never;
1516
1679
  trace?: never;
1517
1680
  };
1518
- "/v1/projections/adaptation-report": {
1681
+ "/v1/recommend-spot": {
1519
1682
  parameters: {
1520
1683
  query?: never;
1521
1684
  header?: never;
@@ -1525,8 +1688,8 @@ export interface paths {
1525
1688
  get?: never;
1526
1689
  put?: never;
1527
1690
  /**
1528
- * Climate adaptation report for an operator (Scale)
1529
- * @description Combines projections across a portfolio + qualitative summary of which dimensions are likely to bind (wind shifts, water-temp shifts, etc.). Designed as input for a tourism-board adaptation plan.
1691
+ * Spot recommender inverse query (L10)
1692
+ * @description Given (activity, region center, radius, window) top-K ranked sub-spots in the catalog. Composition of L1-L3 scoring + L4.6 confidence + L6 personal blend (Pro+, when pseudonym supplied). Plan caps: radius 25/50/200/1000 km, topK 5/10/20/50 across Free / Starter / Pro / Scale. Personalization Pro+ only. Hard-gated candidates (lightning ≥ 0.85, AQI hazardous) are dropped from results; `allGated=true` distinguishes 'all in-radius spots were unsafe' from 'no spots in radius at all'.
1530
1693
  */
1531
1694
  post: {
1532
1695
  parameters: {
@@ -1538,35 +1701,659 @@ export interface paths {
1538
1701
  requestBody: {
1539
1702
  content: {
1540
1703
  "application/json": {
1541
- spots: ({
1542
- location: components["schemas"]["GeoPoint"];
1543
- activity: string;
1544
- spotId?: string;
1545
- subSpotSlug?: string;
1546
- } & {
1547
- [key: string]: unknown;
1548
- })[];
1549
- scenarios: ("SSP1-2.6" | "SSP2-4.5" | "SSP3-7.0" | "SSP5-8.5")[];
1550
- horizonDecades?: string[];
1551
- } & {
1552
- [key: string]: unknown;
1704
+ activity: string;
1705
+ regionCenter: components["schemas"]["GeoPoint"];
1706
+ radiusKm: number;
1707
+ topK: number;
1708
+ window?: components["schemas"]["TimeWindow"];
1709
+ /** @description Optional booking-platform-side pseudonym. When present, Pro+ tenants get personalization via the L6 cold-start blend (cap 0.5 weight). */
1710
+ userPseudonym?: string;
1711
+ };
1712
+ };
1713
+ };
1714
+ responses: {
1715
+ /** @description Ranked top-K sub-spots + observability metadata. The optional `coverage` field appears only on empty results from a catalog gap (not from hard-gating). */
1716
+ 200: {
1717
+ headers: {
1718
+ [name: string]: unknown;
1719
+ };
1720
+ content: {
1721
+ "application/json": {
1722
+ results?: {
1723
+ spotSlug?: string;
1724
+ name?: string;
1725
+ location?: components["schemas"]["GeoPoint"];
1726
+ distanceKm?: number;
1727
+ score?: number;
1728
+ effectiveScore?: number;
1729
+ verdict?: string;
1730
+ personalScore?: number | null;
1731
+ personalWeight?: number;
1732
+ rank?: number;
1733
+ }[];
1734
+ allGated?: boolean;
1735
+ totalCandidates?: number;
1736
+ rankedCandidates?: number;
1737
+ effectiveRadiusKm?: number;
1738
+ effectiveTopK?: number;
1739
+ personalizationApplied?: boolean;
1740
+ latencyMs?: number;
1741
+ coverage?: {
1742
+ /** @enum {string} */
1743
+ status: "no_subspots_in_radius";
1744
+ nearestSubSpot: {
1745
+ slug: string;
1746
+ name: string;
1747
+ distanceKm: number;
1748
+ };
1749
+ /** @enum {string} */
1750
+ suggestedAction: "expand_radius";
1751
+ suggestedRadiusKm: number;
1752
+ } | {
1753
+ /** @enum {string} */
1754
+ status: "no_subspots_for_activity";
1755
+ /** @enum {string} */
1756
+ suggestedAction: "request_coverage";
1757
+ };
1758
+ };
1759
+ };
1760
+ };
1761
+ /** @description Missing/invalid bearer token */
1762
+ 401: {
1763
+ headers: {
1764
+ [name: string]: unknown;
1765
+ };
1766
+ content: {
1767
+ "application/json": components["schemas"]["Error"];
1768
+ };
1769
+ };
1770
+ /** @description Plan limit exceeded (radius or topK above plan cap) */
1771
+ 402: {
1772
+ headers: {
1773
+ [name: string]: unknown;
1774
+ };
1775
+ content: {
1776
+ "application/json": components["schemas"]["Error"];
1553
1777
  };
1554
1778
  };
1779
+ /** @description Validation error or unknown activity */
1780
+ 422: {
1781
+ headers: {
1782
+ [name: string]: unknown;
1783
+ };
1784
+ content: {
1785
+ "application/json": components["schemas"]["Error"];
1786
+ };
1787
+ };
1788
+ /** @description Spatial resolver not wired */
1789
+ 503: {
1790
+ headers: {
1791
+ [name: string]: unknown;
1792
+ };
1793
+ content: {
1794
+ "application/json": components["schemas"]["Error"];
1795
+ };
1796
+ };
1797
+ };
1798
+ };
1799
+ delete?: never;
1800
+ options?: never;
1801
+ head?: never;
1802
+ patch?: never;
1803
+ trace?: never;
1804
+ };
1805
+ "/v1/intelligence/edge-case": {
1806
+ parameters: {
1807
+ query?: never;
1808
+ header?: never;
1809
+ path?: never;
1810
+ cookie?: never;
1811
+ };
1812
+ get?: never;
1813
+ put?: never;
1814
+ /**
1815
+ * LLM analysis of a borderline / surprising score (L2c, Pro+)
1816
+ * @description Asks the LLM to inspect a score that's near a verdict boundary or contradicts operator intuition. Returns a narrative + a structured `limiting_class` taxonomy entry.
1817
+ */
1818
+ post: {
1819
+ parameters: {
1820
+ query?: never;
1821
+ header?: never;
1822
+ path?: never;
1823
+ cookie?: never;
1824
+ };
1825
+ requestBody: {
1826
+ content: {
1827
+ "application/json": {
1828
+ location: components["schemas"]["GeoPoint"];
1829
+ scoreResult?: components["schemas"]["ScoreResponse"];
1830
+ /** Format: uuid */
1831
+ session_id?: string;
1832
+ /** @enum {string} */
1833
+ locale?: "en" | "it";
1834
+ /** @enum {string} */
1835
+ model?: "claude-haiku-4-5-20251001" | "claude-sonnet-4-6";
1836
+ };
1837
+ };
1838
+ };
1839
+ responses: {
1840
+ /** @description Narrative + limiting_class */
1841
+ 200: {
1842
+ headers: {
1843
+ [name: string]: unknown;
1844
+ };
1845
+ content: {
1846
+ "application/json": {
1847
+ [key: string]: unknown;
1848
+ };
1849
+ };
1850
+ };
1851
+ /** @description Requires Pro+ plan */
1852
+ 402: {
1853
+ headers: {
1854
+ [name: string]: unknown;
1855
+ };
1856
+ content: {
1857
+ "application/json": components["schemas"]["Error"];
1858
+ };
1859
+ };
1860
+ /** @description Validation error */
1861
+ 422: {
1862
+ headers: {
1863
+ [name: string]: unknown;
1864
+ };
1865
+ content: {
1866
+ "application/json": components["schemas"]["Error"];
1867
+ };
1868
+ };
1869
+ };
1870
+ };
1871
+ delete?: never;
1872
+ options?: never;
1873
+ head?: never;
1874
+ patch?: never;
1875
+ trace?: never;
1876
+ };
1877
+ "/v1/projections/portfolio": {
1878
+ parameters: {
1879
+ query?: never;
1880
+ header?: never;
1881
+ path?: never;
1882
+ cookie?: never;
1883
+ };
1884
+ get?: never;
1885
+ put?: never;
1886
+ /** Climate projections across a portfolio of spots (Scale) */
1887
+ post: {
1888
+ parameters: {
1889
+ query?: never;
1890
+ header?: never;
1891
+ path?: never;
1892
+ cookie?: never;
1893
+ };
1894
+ requestBody: {
1895
+ content: {
1896
+ "application/json": {
1897
+ spots: {
1898
+ location: components["schemas"]["GeoPoint"];
1899
+ activity: string;
1900
+ spotId?: string;
1901
+ }[];
1902
+ scenarios: ("SSP1-2.6" | "SSP2-4.5" | "SSP3-7.0" | "SSP5-8.5")[];
1903
+ horizonDecades?: string[];
1904
+ /** @enum {string} */
1905
+ baselineDecade?: "2020s" | "2030s";
1906
+ };
1907
+ };
1908
+ };
1909
+ responses: {
1910
+ /** @description Per-spot per-decade projection distributions */
1911
+ 200: {
1912
+ headers: {
1913
+ [name: string]: unknown;
1914
+ };
1915
+ content: {
1916
+ "application/json": {
1917
+ [key: string]: unknown;
1918
+ };
1919
+ };
1920
+ };
1921
+ /** @description Requires Scale plan */
1922
+ 402: {
1923
+ headers: {
1924
+ [name: string]: unknown;
1925
+ };
1926
+ content: {
1927
+ "application/json": components["schemas"]["Error"];
1928
+ };
1929
+ };
1930
+ /** @description Validation error */
1931
+ 422: {
1932
+ headers: {
1933
+ [name: string]: unknown;
1934
+ };
1935
+ content: {
1936
+ "application/json": components["schemas"]["Error"];
1937
+ };
1938
+ };
1939
+ };
1940
+ };
1941
+ delete?: never;
1942
+ options?: never;
1943
+ head?: never;
1944
+ patch?: never;
1945
+ trace?: never;
1946
+ };
1947
+ "/v1/projections/adaptation-report": {
1948
+ parameters: {
1949
+ query?: never;
1950
+ header?: never;
1951
+ path?: never;
1952
+ cookie?: never;
1953
+ };
1954
+ get?: never;
1955
+ put?: never;
1956
+ /**
1957
+ * Climate adaptation report for an operator (Scale)
1958
+ * @description Combines projections across a portfolio + qualitative summary of which dimensions are likely to bind (wind shifts, water-temp shifts, etc.). Designed as input for a tourism-board adaptation plan.
1959
+ */
1960
+ post: {
1961
+ parameters: {
1962
+ query?: never;
1963
+ header?: never;
1964
+ path?: never;
1965
+ cookie?: never;
1966
+ };
1967
+ requestBody: {
1968
+ content: {
1969
+ "application/json": {
1970
+ spots: ({
1971
+ location: components["schemas"]["GeoPoint"];
1972
+ activity: string;
1973
+ spotId?: string;
1974
+ subSpotSlug?: string;
1975
+ } & {
1976
+ [key: string]: unknown;
1977
+ })[];
1978
+ scenarios: ("SSP1-2.6" | "SSP2-4.5" | "SSP3-7.0" | "SSP5-8.5")[];
1979
+ horizonDecades?: string[];
1980
+ } & {
1981
+ [key: string]: unknown;
1982
+ };
1983
+ };
1984
+ };
1985
+ responses: {
1986
+ /** @description Adaptation report + binding-dimension summary */
1987
+ 200: {
1988
+ headers: {
1989
+ [name: string]: unknown;
1990
+ };
1991
+ content: {
1992
+ "application/json": {
1993
+ [key: string]: unknown;
1994
+ };
1995
+ };
1996
+ };
1997
+ /** @description Requires Scale plan */
1998
+ 402: {
1999
+ headers: {
2000
+ [name: string]: unknown;
2001
+ };
2002
+ content: {
2003
+ "application/json": components["schemas"]["Error"];
2004
+ };
2005
+ };
2006
+ /** @description Validation error */
2007
+ 422: {
2008
+ headers: {
2009
+ [name: string]: unknown;
2010
+ };
2011
+ content: {
2012
+ "application/json": components["schemas"]["Error"];
2013
+ };
2014
+ };
2015
+ };
2016
+ };
2017
+ delete?: never;
2018
+ options?: never;
2019
+ head?: never;
2020
+ patch?: never;
2021
+ trace?: never;
2022
+ };
2023
+ "/v1/observations": {
2024
+ parameters: {
2025
+ query?: never;
2026
+ header?: never;
2027
+ path?: never;
2028
+ cookie?: never;
2029
+ };
2030
+ get?: never;
2031
+ put?: never;
2032
+ /**
2033
+ * Submit station observations for data assimilation (Pro+)
2034
+ * @description Push tenant-station observations (wind / wave / temperature / etc.) into the 0-6h assimilation window. The optimal-interpolation blending pulls them into forecast samples for nearby spots, improving short-horizon skill.
2035
+ */
2036
+ post: {
2037
+ parameters: {
2038
+ query?: never;
2039
+ header?: never;
2040
+ path?: never;
2041
+ cookie?: never;
2042
+ };
2043
+ requestBody: {
2044
+ content: {
2045
+ "application/json": {
2046
+ /** Format: uuid */
2047
+ stationId: string;
2048
+ observations: {
2049
+ /** Format: date-time */
2050
+ observedAt: string;
2051
+ /** @enum {string} */
2052
+ variable: "wind_speed_kn" | "wind_dir_deg" | "wave_height_m" | "temp_c" | "sea_surface_temp_c" | "pressure_hpa" | "precip_mm";
2053
+ value: number;
2054
+ /** @enum {string} */
2055
+ qualityFlag?: "verified" | "unflagged" | "flagged_low_quality";
2056
+ }[];
2057
+ };
2058
+ };
2059
+ };
2060
+ responses: {
2061
+ /** @description Accepted */
2062
+ 202: {
2063
+ headers: {
2064
+ [name: string]: unknown;
2065
+ };
2066
+ content: {
2067
+ "application/json": {
2068
+ [key: string]: unknown;
2069
+ };
2070
+ };
2071
+ };
2072
+ /** @description Requires Pro+ plan */
2073
+ 402: {
2074
+ headers: {
2075
+ [name: string]: unknown;
2076
+ };
2077
+ content: {
2078
+ "application/json": components["schemas"]["Error"];
2079
+ };
2080
+ };
2081
+ /** @description Station not found */
2082
+ 404: {
2083
+ headers: {
2084
+ [name: string]: unknown;
2085
+ };
2086
+ content: {
2087
+ "application/json": components["schemas"]["Error"];
2088
+ };
2089
+ };
2090
+ /** @description Station inactive */
2091
+ 409: {
2092
+ headers: {
2093
+ [name: string]: unknown;
2094
+ };
2095
+ content: {
2096
+ "application/json": components["schemas"]["Error"];
2097
+ };
2098
+ };
2099
+ /** @description Validation error / observation in future / variable mismatch */
2100
+ 422: {
2101
+ headers: {
2102
+ [name: string]: unknown;
2103
+ };
2104
+ content: {
2105
+ "application/json": components["schemas"]["Error"];
2106
+ };
2107
+ };
2108
+ /** @description Observation store not wired */
2109
+ 503: {
2110
+ headers: {
2111
+ [name: string]: unknown;
2112
+ };
2113
+ content: {
2114
+ "application/json": components["schemas"]["Error"];
2115
+ };
2116
+ };
2117
+ };
2118
+ };
2119
+ delete?: never;
2120
+ options?: never;
2121
+ head?: never;
2122
+ patch?: never;
2123
+ trace?: never;
2124
+ };
2125
+ "/v1/observations/stations": {
2126
+ parameters: {
2127
+ query?: never;
2128
+ header?: never;
2129
+ path?: never;
2130
+ cookie?: never;
2131
+ };
2132
+ /** List tenant stations */
2133
+ get: {
2134
+ parameters: {
2135
+ query?: never;
2136
+ header?: never;
2137
+ path?: never;
2138
+ cookie?: never;
2139
+ };
2140
+ requestBody?: never;
2141
+ responses: {
2142
+ /** @description Array of stations */
2143
+ 200: {
2144
+ headers: {
2145
+ [name: string]: unknown;
2146
+ };
2147
+ content: {
2148
+ "application/json": {
2149
+ [key: string]: unknown;
2150
+ };
2151
+ };
2152
+ };
2153
+ /** @description Station registry not wired */
2154
+ 503: {
2155
+ headers: {
2156
+ [name: string]: unknown;
2157
+ };
2158
+ content: {
2159
+ "application/json": components["schemas"]["Error"];
2160
+ };
2161
+ };
2162
+ };
2163
+ };
2164
+ put?: never;
2165
+ /** Register a tenant observation station */
2166
+ post: {
2167
+ parameters: {
2168
+ query?: never;
2169
+ header?: never;
2170
+ path?: never;
2171
+ cookie?: never;
2172
+ };
2173
+ requestBody: {
2174
+ content: {
2175
+ "application/json": {
2176
+ name: string;
2177
+ point: components["schemas"]["GeoPoint"];
2178
+ altitudeM?: number;
2179
+ variables: ("wind_speed_kn" | "wind_dir_deg" | "wave_height_m" | "temp_c" | "sea_surface_temp_c" | "pressure_hpa" | "precip_mm")[];
2180
+ /** @enum {string} */
2181
+ stationClass?: "verified" | "unflagged" | "flagged_low_quality";
2182
+ updateCadenceMinutes?: number;
2183
+ notes?: string;
2184
+ };
2185
+ };
2186
+ };
2187
+ responses: {
2188
+ /** @description Station created */
2189
+ 201: {
2190
+ headers: {
2191
+ [name: string]: unknown;
2192
+ };
2193
+ content: {
2194
+ "application/json": {
2195
+ [key: string]: unknown;
2196
+ };
2197
+ };
2198
+ };
2199
+ /** @description Validation error */
2200
+ 422: {
2201
+ headers: {
2202
+ [name: string]: unknown;
2203
+ };
2204
+ content: {
2205
+ "application/json": components["schemas"]["Error"];
2206
+ };
2207
+ };
2208
+ /** @description Station registry not wired */
2209
+ 503: {
2210
+ headers: {
2211
+ [name: string]: unknown;
2212
+ };
2213
+ content: {
2214
+ "application/json": components["schemas"]["Error"];
2215
+ };
2216
+ };
2217
+ };
2218
+ };
2219
+ delete?: never;
2220
+ options?: never;
2221
+ head?: never;
2222
+ patch?: never;
2223
+ trace?: never;
2224
+ };
2225
+ "/v1/observations/stations/{stationId}": {
2226
+ parameters: {
2227
+ query?: never;
2228
+ header?: never;
2229
+ path?: never;
2230
+ cookie?: never;
2231
+ };
2232
+ get?: never;
2233
+ put?: never;
2234
+ post?: never;
2235
+ delete?: never;
2236
+ options?: never;
2237
+ head?: never;
2238
+ /** Update a station */
2239
+ patch: {
2240
+ parameters: {
2241
+ query?: never;
2242
+ header?: never;
2243
+ path: {
2244
+ stationId: string;
2245
+ };
2246
+ cookie?: never;
2247
+ };
2248
+ requestBody: {
2249
+ content: {
2250
+ "application/json": {
2251
+ name?: string;
2252
+ point?: components["schemas"]["GeoPoint"];
2253
+ altitudeM?: number;
2254
+ variables?: ("wind_speed_kn" | "wind_dir_deg" | "wave_height_m" | "temp_c" | "sea_surface_temp_c" | "pressure_hpa" | "precip_mm")[];
2255
+ /** @enum {string} */
2256
+ stationClass?: "verified" | "unflagged" | "flagged_low_quality";
2257
+ updateCadenceMinutes?: number;
2258
+ active?: boolean;
2259
+ notes?: string;
2260
+ };
2261
+ };
2262
+ };
2263
+ responses: {
2264
+ /** @description Updated station */
2265
+ 200: {
2266
+ headers: {
2267
+ [name: string]: unknown;
2268
+ };
2269
+ content: {
2270
+ "application/json": {
2271
+ [key: string]: unknown;
2272
+ };
2273
+ };
2274
+ };
2275
+ /** @description Station not found */
2276
+ 404: {
2277
+ headers: {
2278
+ [name: string]: unknown;
2279
+ };
2280
+ content: {
2281
+ "application/json": components["schemas"]["Error"];
2282
+ };
2283
+ };
2284
+ /** @description Validation error */
2285
+ 422: {
2286
+ headers: {
2287
+ [name: string]: unknown;
2288
+ };
2289
+ content: {
2290
+ "application/json": components["schemas"]["Error"];
2291
+ };
2292
+ };
2293
+ /** @description Station registry not wired */
2294
+ 503: {
2295
+ headers: {
2296
+ [name: string]: unknown;
2297
+ };
2298
+ content: {
2299
+ "application/json": components["schemas"]["Error"];
2300
+ };
2301
+ };
2302
+ };
2303
+ };
2304
+ trace?: never;
2305
+ };
2306
+ "/v1/observations/stations/{stationId}/recent": {
2307
+ parameters: {
2308
+ query?: never;
2309
+ header?: never;
2310
+ path?: never;
2311
+ cookie?: never;
2312
+ };
2313
+ /**
2314
+ * Recent observations for a tenant station
2315
+ * @description Returns up to `limit` most-recent observations submitted for the station (tenant-scoped). Useful for the tenant's own dashboard / debugging feed. Requires the `score:read` scope.
2316
+ */
2317
+ get: {
2318
+ parameters: {
2319
+ query?: {
2320
+ limit?: number;
2321
+ };
2322
+ header?: never;
2323
+ path: {
2324
+ stationId: string;
2325
+ };
2326
+ cookie?: never;
1555
2327
  };
2328
+ requestBody?: never;
1556
2329
  responses: {
1557
- /** @description Adaptation report + binding-dimension summary */
2330
+ /** @description Most-recent observations for this station (descending by observedAt) */
1558
2331
  200: {
1559
2332
  headers: {
1560
2333
  [name: string]: unknown;
1561
2334
  };
1562
2335
  content: {
1563
2336
  "application/json": {
1564
- [key: string]: unknown;
2337
+ observations: {
2338
+ /** Format: uuid */
2339
+ id: string;
2340
+ /** Format: uuid */
2341
+ stationId: string;
2342
+ /** Format: date-time */
2343
+ observedAt: string;
2344
+ /** @enum {string} */
2345
+ variable: "wind_speed_kn" | "wind_dir_deg" | "wave_height_m" | "temp_c" | "sea_surface_temp_c" | "pressure_hpa" | "precip_mm";
2346
+ value: number;
2347
+ /** @enum {string|null} */
2348
+ qualityFlag?: "verified" | "unflagged" | "flagged_low_quality" | null;
2349
+ /** Format: date-time */
2350
+ ingestedAt: string;
2351
+ }[];
1565
2352
  };
1566
2353
  };
1567
2354
  };
1568
- /** @description Requires Scale plan */
1569
- 402: {
2355
+ /** @description Station not found */
2356
+ 404: {
1570
2357
  headers: {
1571
2358
  [name: string]: unknown;
1572
2359
  };
@@ -1574,8 +2361,8 @@ export interface paths {
1574
2361
  "application/json": components["schemas"]["Error"];
1575
2362
  };
1576
2363
  };
1577
- /** @description Validation error */
1578
- 422: {
2364
+ /** @description Observation store not wired */
2365
+ 503: {
1579
2366
  headers: {
1580
2367
  [name: string]: unknown;
1581
2368
  };
@@ -1585,13 +2372,15 @@ export interface paths {
1585
2372
  };
1586
2373
  };
1587
2374
  };
2375
+ put?: never;
2376
+ post?: never;
1588
2377
  delete?: never;
1589
2378
  options?: never;
1590
2379
  head?: never;
1591
2380
  patch?: never;
1592
2381
  trace?: never;
1593
2382
  };
1594
- "/v1/observations": {
2383
+ "/v1/public/signup": {
1595
2384
  parameters: {
1596
2385
  query?: never;
1597
2386
  header?: never;
@@ -1601,8 +2390,8 @@ export interface paths {
1601
2390
  get?: never;
1602
2391
  put?: never;
1603
2392
  /**
1604
- * Submit station observation for data assimilation (Pro+)
1605
- * @description Push tenant-station observations (wind / wave / temperature / etc.) into the 0-6h assimilation window. The optimal-interpolation blending pulls them into forecast samples for nearby spots, improving short-horizon skill.
2393
+ * Self-service tenant signup (no auth)
2394
+ * @description Public endpoint, IP-rate-limited (3 attempts / 24h / IP). Creates a tenant + sends a magic-link to the contact email. Always returns 202 on success never reveals whether an email is already registered. Optional Cloudflare Turnstile token strengthens the gate.
1606
2395
  */
1607
2396
  post: {
1608
2397
  parameters: {
@@ -1614,21 +2403,20 @@ export interface paths {
1614
2403
  requestBody: {
1615
2404
  content: {
1616
2405
  "application/json": {
1617
- /** Format: uuid */
1618
- stationId: string;
1619
- /** Format: date-time */
1620
- observedAt: string;
1621
- values: {
1622
- [key: string]: number;
1623
- };
1624
- qualityFlags?: {
1625
- [key: string]: unknown;
1626
- };
2406
+ displayName: string;
2407
+ /** Format: email */
2408
+ contactEmail: string;
2409
+ /**
2410
+ * @description Must be true — records ToS / Privacy / DPA acceptance.
2411
+ * @enum {boolean}
2412
+ */
2413
+ acceptTerms: true;
2414
+ turnstileToken?: string;
1627
2415
  };
1628
2416
  };
1629
2417
  };
1630
2418
  responses: {
1631
- /** @description Accepted */
2419
+ /** @description Accepted — magic-link sent if signup valid */
1632
2420
  202: {
1633
2421
  headers: {
1634
2422
  [name: string]: unknown;
@@ -1639,17 +2427,8 @@ export interface paths {
1639
2427
  };
1640
2428
  };
1641
2429
  };
1642
- /** @description Requires Pro+ plan */
1643
- 402: {
1644
- headers: {
1645
- [name: string]: unknown;
1646
- };
1647
- content: {
1648
- "application/json": components["schemas"]["Error"];
1649
- };
1650
- };
1651
- /** @description Station not found */
1652
- 404: {
2430
+ /** @description Validation error */
2431
+ 422: {
1653
2432
  headers: {
1654
2433
  [name: string]: unknown;
1655
2434
  };
@@ -1657,8 +2436,8 @@ export interface paths {
1657
2436
  "application/json": components["schemas"]["Error"];
1658
2437
  };
1659
2438
  };
1660
- /** @description Validation error */
1661
- 422: {
2439
+ /** @description IP rate limit exceeded */
2440
+ 429: {
1662
2441
  headers: {
1663
2442
  [name: string]: unknown;
1664
2443
  };
@@ -1674,73 +2453,92 @@ export interface paths {
1674
2453
  patch?: never;
1675
2454
  trace?: never;
1676
2455
  };
1677
- "/v1/observations/stations": {
2456
+ "/v1/public/sustainability-index": {
1678
2457
  parameters: {
1679
2458
  query?: never;
1680
2459
  header?: never;
1681
2460
  path?: never;
1682
2461
  cookie?: never;
1683
2462
  };
1684
- /** List tenant stations */
2463
+ /**
2464
+ * Public Goable Sustainability Index (no auth, JSON-LD)
2465
+ * @description Public JSON-LD artefact of the Goable Sustainability Index (CC BY 4.0). Session-weighted 0-100 index across zones plus per-zone breakdowns. Governed by k-anonymity (default k≥10) + a 90-day publication lag in the underlying reader — no additional privacy work required for the public surface. Content-Type: application/ld+json. Edge-cached for 5 minutes.
2466
+ */
1685
2467
  get: {
1686
2468
  parameters: {
1687
- query?: never;
2469
+ query: {
2470
+ /** @description Inclusive start of the reporting period. */
2471
+ from: string;
2472
+ /** @description Exclusive end of the reporting period. */
2473
+ to: string;
2474
+ /** @description Zone grid cell edge length in km (default: reader-configured). */
2475
+ zoneKm?: number;
2476
+ /** @description k-anonymity threshold: zones with fewer than k sessions are suppressed. */
2477
+ k?: number;
2478
+ };
1688
2479
  header?: never;
1689
2480
  path?: never;
1690
2481
  cookie?: never;
1691
2482
  };
1692
2483
  requestBody?: never;
1693
2484
  responses: {
1694
- /** @description Array of stations */
2485
+ /** @description Sustainability Index document (JSON-LD) */
1695
2486
  200: {
1696
2487
  headers: {
1697
2488
  [name: string]: unknown;
1698
2489
  };
1699
2490
  content: {
1700
- "application/json": {
1701
- [key: string]: unknown;
1702
- };
1703
- };
1704
- };
1705
- };
1706
- };
1707
- put?: never;
1708
- /** Register a tenant observation station (Pro+) */
1709
- post: {
1710
- parameters: {
1711
- query?: never;
1712
- header?: never;
1713
- path?: never;
1714
- cookie?: never;
1715
- };
1716
- requestBody: {
1717
- content: {
1718
- "application/json": {
1719
- name: string;
1720
- location: components["schemas"]["GeoPoint"];
1721
- elevationM?: number;
1722
- metadata?: {
1723
- [key: string]: unknown;
1724
- };
1725
- } & {
1726
- [key: string]: unknown;
1727
- };
1728
- };
1729
- };
1730
- responses: {
1731
- /** @description Station created */
1732
- 201: {
1733
- headers: {
1734
- [name: string]: unknown;
1735
- };
1736
- content: {
1737
- "application/json": {
2491
+ "application/ld+json": {
2492
+ /** @example https://schema.org */
2493
+ "@context": string;
2494
+ /** @enum {string} */
2495
+ "@type": "GoableSustainabilityIndex";
2496
+ /** Format: date-time */
2497
+ generatedAt: string;
2498
+ period: {
2499
+ /** Format: date-time */
2500
+ from: string;
2501
+ /** Format: date-time */
2502
+ to: string;
2503
+ };
2504
+ methodology: {
2505
+ indexFormula: string;
2506
+ weights: {
2507
+ carbonNeutralShare: number;
2508
+ electrificationShare: number;
2509
+ };
2510
+ suppression: string;
2511
+ notes: string;
2512
+ };
2513
+ overall: {
2514
+ index: number;
2515
+ totalSessions: number;
2516
+ carbonNeutralSessions: number;
2517
+ carbonPositiveSessions: number;
2518
+ carbonNeutralShare: number;
2519
+ zonesReleased: number;
2520
+ zonesSuppressed: number;
2521
+ };
2522
+ zones: {
2523
+ zoneKey: string;
2524
+ label: string | null;
2525
+ centroid: components["schemas"]["GeoPoint"] | null;
2526
+ totalSessions: number;
2527
+ carbonNeutralShare: number;
2528
+ electrificationShare: number | null;
2529
+ seasonalConcentration: number | null;
2530
+ zoneIndex: number;
2531
+ }[];
2532
+ /** @enum {string} */
2533
+ license: "CC BY 4.0";
2534
+ attribution: string;
2535
+ } & {
1738
2536
  [key: string]: unknown;
1739
2537
  };
1740
2538
  };
1741
2539
  };
1742
- /** @description Requires Pro+ plan */
1743
- 402: {
2540
+ /** @description Validation error */
2541
+ 422: {
1744
2542
  headers: {
1745
2543
  [name: string]: unknown;
1746
2544
  };
@@ -1748,8 +2546,8 @@ export interface paths {
1748
2546
  "application/json": components["schemas"]["Error"];
1749
2547
  };
1750
2548
  };
1751
- /** @description Validation error */
1752
- 422: {
2549
+ /** @description Sustainability index reader not wired */
2550
+ 503: {
1753
2551
  headers: {
1754
2552
  [name: string]: unknown;
1755
2553
  };
@@ -1759,63 +2557,48 @@ export interface paths {
1759
2557
  };
1760
2558
  };
1761
2559
  };
2560
+ put?: never;
2561
+ post?: never;
1762
2562
  delete?: never;
1763
2563
  options?: never;
1764
2564
  head?: never;
1765
2565
  patch?: never;
1766
2566
  trace?: never;
1767
2567
  };
1768
- "/v1/observations/stations/{stationId}": {
2568
+ "/v1/research/verification/export": {
1769
2569
  parameters: {
1770
2570
  query?: never;
1771
2571
  header?: never;
1772
2572
  path?: never;
1773
2573
  cookie?: never;
1774
2574
  };
1775
- get?: never;
1776
- put?: never;
1777
- post?: never;
1778
- delete?: never;
1779
- options?: never;
1780
- head?: never;
1781
- /** Update a station (Pro+) */
1782
- patch: {
2575
+ /**
2576
+ * Public Stream F forecast verification export (no auth, JSONL)
2577
+ * @description Streamed newline-delimited JSON (`application/x-ndjson`) — one anonymised (activity × 1km² grid × weekly bucket) skill cell per line, followed by a trailing metadata line. CC BY 4.0. Governance: k≥10 contributor floor + 90-day publication lag + `research_eligible=true` filter enforced in the SQL reader.
2578
+ */
2579
+ get: {
1783
2580
  parameters: {
1784
- query?: never;
1785
- header?: never;
1786
- path: {
1787
- stationId: string;
2581
+ query?: {
2582
+ from?: string;
2583
+ to?: string;
1788
2584
  };
2585
+ header?: never;
2586
+ path?: never;
1789
2587
  cookie?: never;
1790
2588
  };
1791
- requestBody: {
1792
- content: {
1793
- "application/json": {
1794
- name?: string;
1795
- location?: components["schemas"]["GeoPoint"];
1796
- elevationM?: number;
1797
- metadata?: {
1798
- [key: string]: unknown;
1799
- };
1800
- } & {
1801
- [key: string]: unknown;
1802
- };
1803
- };
1804
- };
2589
+ requestBody?: never;
1805
2590
  responses: {
1806
- /** @description Updated station */
2591
+ /** @description Streamed JSONL — one cell per line + trailing meta line */
1807
2592
  200: {
1808
2593
  headers: {
1809
2594
  [name: string]: unknown;
1810
2595
  };
1811
2596
  content: {
1812
- "application/json": {
1813
- [key: string]: unknown;
1814
- };
2597
+ "application/x-ndjson": string;
1815
2598
  };
1816
2599
  };
1817
- /** @description Requires Pro+ plan */
1818
- 402: {
2600
+ /** @description Validation error */
2601
+ 422: {
1819
2602
  headers: {
1820
2603
  [name: string]: unknown;
1821
2604
  };
@@ -1823,8 +2606,8 @@ export interface paths {
1823
2606
  "application/json": components["schemas"]["Error"];
1824
2607
  };
1825
2608
  };
1826
- /** @description Station not found */
1827
- 404: {
2609
+ /** @description Verification reader not wired */
2610
+ 503: {
1828
2611
  headers: {
1829
2612
  [name: string]: unknown;
1830
2613
  };
@@ -1834,66 +2617,45 @@ export interface paths {
1834
2617
  };
1835
2618
  };
1836
2619
  };
2620
+ put?: never;
2621
+ post?: never;
2622
+ delete?: never;
2623
+ options?: never;
2624
+ head?: never;
2625
+ patch?: never;
1837
2626
  trace?: never;
1838
2627
  };
1839
- "/v1/public/signup": {
2628
+ "/v1/research/difficulty-atlas/export.jsonl": {
1840
2629
  parameters: {
1841
2630
  query?: never;
1842
2631
  header?: never;
1843
2632
  path?: never;
1844
2633
  cookie?: never;
1845
2634
  };
1846
- get?: never;
1847
- put?: never;
1848
2635
  /**
1849
- * Self-service tenant signup (no auth)
1850
- * @description Public endpoint, IP-rate-limited (3 attempts / 24h / IP). Creates a tenant + sends a magic-link to the contact email. Always returns 202 on success never reveals whether an email is already registered. Optional Cloudflare Turnstile token strengthens the gate.
2636
+ * Public L15 Difficulty Atlas export (no auth, JSONL)
2637
+ * @description Streamed newline-delimited JSON (`application/x-ndjson`) — one anonymised (activity × sub-spot × dimension) difficulty row per line, followed by a trailing metadata line. CC BY 4.0. First openly-available intrinsic-difficulty measurement for outdoor activities. Governance mirrors Stream F: k≥10 contributors + 90-day publication lag.
1851
2638
  */
1852
- post: {
2639
+ get: {
1853
2640
  parameters: {
1854
2641
  query?: never;
1855
2642
  header?: never;
1856
2643
  path?: never;
1857
2644
  cookie?: never;
1858
2645
  };
1859
- requestBody: {
1860
- content: {
1861
- "application/json": {
1862
- displayName: string;
1863
- /** Format: email */
1864
- contactEmail: string;
1865
- /**
1866
- * @description Must be true — records ToS / Privacy / DPA acceptance.
1867
- * @enum {boolean}
1868
- */
1869
- acceptTerms: true;
1870
- turnstileToken?: string;
1871
- };
1872
- };
1873
- };
2646
+ requestBody?: never;
1874
2647
  responses: {
1875
- /** @description Acceptedmagic-link sent if signup valid */
1876
- 202: {
1877
- headers: {
1878
- [name: string]: unknown;
1879
- };
1880
- content: {
1881
- "application/json": {
1882
- [key: string]: unknown;
1883
- };
1884
- };
1885
- };
1886
- /** @description Validation error */
1887
- 422: {
2648
+ /** @description Streamed JSONL one atlas row per line + trailing meta line */
2649
+ 200: {
1888
2650
  headers: {
1889
2651
  [name: string]: unknown;
1890
2652
  };
1891
2653
  content: {
1892
- "application/json": components["schemas"]["Error"];
2654
+ "application/x-ndjson": string;
1893
2655
  };
1894
2656
  };
1895
- /** @description IP rate limit exceeded */
1896
- 429: {
2657
+ /** @description Difficulty atlas reader not wired */
2658
+ 503: {
1897
2659
  headers: {
1898
2660
  [name: string]: unknown;
1899
2661
  };
@@ -1903,6 +2665,8 @@ export interface paths {
1903
2665
  };
1904
2666
  };
1905
2667
  };
2668
+ put?: never;
2669
+ post?: never;
1906
2670
  delete?: never;
1907
2671
  options?: never;
1908
2672
  head?: never;
@@ -2048,12 +2812,8 @@ export interface components {
2048
2812
  distribution?: {
2049
2813
  [key: string]: unknown;
2050
2814
  };
2051
- confidenceDetail?: {
2052
- [key: string]: unknown;
2053
- };
2054
- calibration_provenance?: {
2055
- [key: string]: unknown;
2056
- };
2815
+ confidenceDetail?: components["schemas"]["ConfidenceDetailForecast"];
2816
+ calibration_provenance?: components["schemas"]["CalibrationProvenance"] | null;
2057
2817
  assimilation?: {
2058
2818
  [key: string]: unknown;
2059
2819
  };
@@ -2083,6 +2843,297 @@ export interface components {
2083
2843
  } & {
2084
2844
  [key: string]: unknown;
2085
2845
  };
2846
+ CalibrationProvenance: {
2847
+ /** @enum {string} */
2848
+ level?: "sub-spot" | "cluster" | "region" | "base";
2849
+ slug?: string;
2850
+ scoring_profile_slug?: string;
2851
+ sub_spot_slug?: string;
2852
+ distance_to_sub_spot_m?: number;
2853
+ /** @enum {integer} */
2854
+ tier?: 1 | 2 | 3;
2855
+ /** @enum {string} */
2856
+ tier_source?: "catalog" | "classifier";
2857
+ };
2858
+ CalibrationProvenanceSummary: {
2859
+ /** @enum {string} */
2860
+ level: "base" | "region" | "cluster" | "sub-spot";
2861
+ n_local: number | null;
2862
+ shrinkage_weight_from_parent: number | null;
2863
+ };
2864
+ DriftFlag: {
2865
+ /** @enum {string} */
2866
+ severity: "watch" | "warning" | "critical";
2867
+ /** Format: date-time */
2868
+ since_timestamp: string;
2869
+ };
2870
+ ConfidenceDetail: components["schemas"]["ConfidenceDetailForecast"] | components["schemas"]["ConfidenceDetailHistorical"] | components["schemas"]["ConfidenceDetailClimate"];
2871
+ ConfidenceDetailForecast: {
2872
+ /**
2873
+ * @description discriminator enum property added by openapi-typescript
2874
+ * @enum {string}
2875
+ */
2876
+ mode: "forecast";
2877
+ forecast_skill: number;
2878
+ provider_agreement: number;
2879
+ profile_maturity: number;
2880
+ hierarchical_calibration: number;
2881
+ calibration_provenance?: components["schemas"]["CalibrationProvenanceSummary"];
2882
+ skill_calibration?: {
2883
+ applied: boolean;
2884
+ n_train: number;
2885
+ cohort_hash: string;
2886
+ scalar: number;
2887
+ };
2888
+ drift_flag?: components["schemas"]["DriftFlag"];
2889
+ } & {
2890
+ [key: string]: unknown;
2891
+ };
2892
+ ConfidenceDetailHistorical: {
2893
+ /**
2894
+ * @description discriminator enum property added by openapi-typescript
2895
+ * @enum {string}
2896
+ */
2897
+ mode: "historical";
2898
+ sample_size_confidence: number;
2899
+ base_climatology_quality: number;
2900
+ calibration_confidence: number;
2901
+ hierarchical_calibration: number;
2902
+ calibration_provenance?: components["schemas"]["CalibrationProvenanceSummary"];
2903
+ drift_flag?: components["schemas"]["DriftFlag"];
2904
+ } & {
2905
+ [key: string]: unknown;
2906
+ };
2907
+ ConfidenceDetailClimate: {
2908
+ /**
2909
+ * @description discriminator enum property added by openapi-typescript
2910
+ * @enum {string}
2911
+ */
2912
+ mode: "climate";
2913
+ model_spread: number;
2914
+ bias_correction_residual: number;
2915
+ scenario_uncertainty: number;
2916
+ horizon_uncertainty: number;
2917
+ hierarchical_calibration: number;
2918
+ calibration_provenance?: components["schemas"]["CalibrationProvenanceSummary"];
2919
+ drift_flag?: components["schemas"]["DriftFlag"];
2920
+ } & {
2921
+ [key: string]: unknown;
2922
+ };
2923
+ SerialisedPolicy: {
2924
+ /** Format: uuid */
2925
+ id: string;
2926
+ /** Format: uuid */
2927
+ tenantId: string;
2928
+ /** Format: uuid */
2929
+ quoteId: string;
2930
+ /** @enum {string} */
2931
+ status: "bound" | "triggered" | "settled" | "expired";
2932
+ /** @description Null for mixed-currency portfolios; the breakdown lives on the underlying quote. */
2933
+ payoutAmount?: number | null;
2934
+ payoutCurrency?: ("EUR" | "USD" | "GBP" | "CHF") | null;
2935
+ premiumPaid?: number | null;
2936
+ /** @enum {string} */
2937
+ premiumCollection: "external" | "stripe" | "invoice_due";
2938
+ coverageWindow: {
2939
+ monthFrom: number;
2940
+ dayFrom: number;
2941
+ monthTo: number;
2942
+ dayTo: number;
2943
+ };
2944
+ coverageYear: number;
2945
+ /** @description Frozen at bind time — same shape as the quote's normalised trigger. */
2946
+ trigger: {
2947
+ [key: string]: unknown;
2948
+ };
2949
+ /** @description Frozen snapshot of the per-spot profile + payout terms — decouples the policy from later catalog changes. */
2950
+ policyTerms: {
2951
+ [key: string]: unknown;
2952
+ };
2953
+ /** Format: date-time */
2954
+ boundAt: string;
2955
+ /** Format: date-time */
2956
+ triggeredAt: string | null;
2957
+ /** Format: date-time */
2958
+ settledAt: string | null;
2959
+ /** Format: date-time */
2960
+ expiredAt: string | null;
2961
+ settlementReference: string | null;
2962
+ };
2963
+ SerialisedPayoutEvent: {
2964
+ /** Format: uuid */
2965
+ id: string;
2966
+ /** Format: uuid */
2967
+ policyId: string;
2968
+ spotIndex: number;
2969
+ /** Format: date-time */
2970
+ eventStartAt: string;
2971
+ /** Format: date-time */
2972
+ eventEndAt: string;
2973
+ hoursFired: number;
2974
+ payoutAmount: number;
2975
+ /** @enum {string} */
2976
+ payoutCurrency: "EUR" | "USD" | "GBP" | "CHF";
2977
+ /** Format: date-time */
2978
+ detectedAt: string;
2979
+ /** @enum {string} */
2980
+ evaluationSource: "manual" | "scheduled";
2981
+ };
2982
+ UnderwritingQuoteResponse: {
2983
+ policy: {
2984
+ coverageWindow: {
2985
+ monthFrom: number;
2986
+ dayFrom: number;
2987
+ monthTo: number;
2988
+ dayTo: number;
2989
+ };
2990
+ /** @description Normalised trigger echoed back with defaulted consecutiveHours/cooldownHours. */
2991
+ trigger: {
2992
+ [key: string]: unknown;
2993
+ };
2994
+ historicalYearsRange: {
2995
+ from: number;
2996
+ to: number;
2997
+ };
2998
+ spot?: {
2999
+ resolvedProfileSlug: string;
3000
+ point: components["schemas"]["GeoPoint"];
3001
+ spotId?: string;
3002
+ payout: {
3003
+ amount: number;
3004
+ /** @enum {string} */
3005
+ currency: "EUR" | "USD" | "GBP" | "CHF";
3006
+ };
3007
+ /**
3008
+ * @description Sub-spot tier (1/2/3) applied to the tier risk multiplier; null when no sub-spot resolved.
3009
+ * @enum {integer|null}
3010
+ */
3011
+ tier?: 1 | 2 | 3 | null;
3012
+ /**
3013
+ * @description Provenance of the tier: 'catalog' from profile YAML, 'classifier' from L11 confidence=1.0 override, null when no tier applied.
3014
+ * @enum {string|null}
3015
+ */
3016
+ tierSource?: "catalog" | "classifier" | null;
3017
+ };
3018
+ portfolio?: {
3019
+ resolvedProfileSlug: string;
3020
+ point: components["schemas"]["GeoPoint"];
3021
+ spotId?: string;
3022
+ payout: {
3023
+ amount: number;
3024
+ /** @enum {string} */
3025
+ currency: "EUR" | "USD" | "GBP" | "CHF";
3026
+ };
3027
+ /**
3028
+ * @description Sub-spot tier (1/2/3) applied to the tier risk multiplier; null when no sub-spot resolved.
3029
+ * @enum {integer|null}
3030
+ */
3031
+ tier?: 1 | 2 | 3 | null;
3032
+ /**
3033
+ * @description Provenance of the tier: 'catalog' from profile YAML, 'classifier' from L11 confidence=1.0 override, null when no tier applied.
3034
+ * @enum {string|null}
3035
+ */
3036
+ tierSource?: "catalog" | "classifier" | null;
3037
+ }[];
3038
+ } & {
3039
+ [key: string]: unknown;
3040
+ };
3041
+ expectedPayouts: {
3042
+ byCurrency: {
3043
+ EUR?: {
3044
+ mean: number;
3045
+ p10: number;
3046
+ p50: number;
3047
+ p90: number;
3048
+ perYear: number[];
3049
+ varianceStability: number;
3050
+ };
3051
+ USD?: {
3052
+ mean: number;
3053
+ p10: number;
3054
+ p50: number;
3055
+ p90: number;
3056
+ perYear: number[];
3057
+ varianceStability: number;
3058
+ };
3059
+ GBP?: {
3060
+ mean: number;
3061
+ p10: number;
3062
+ p50: number;
3063
+ p90: number;
3064
+ perYear: number[];
3065
+ varianceStability: number;
3066
+ };
3067
+ CHF?: {
3068
+ mean: number;
3069
+ p10: number;
3070
+ p50: number;
3071
+ p90: number;
3072
+ perYear: number[];
3073
+ varianceStability: number;
3074
+ };
3075
+ };
3076
+ };
3077
+ expectedPremium: {
3078
+ byCurrency: {
3079
+ EUR?: {
3080
+ fair: number;
3081
+ loaded: number;
3082
+ /** @description Weighted-average tier risk multiplier applied across spots in this currency (1.0 when no sub-spot). */
3083
+ tierMultiplierWeightedAvg: number;
3084
+ };
3085
+ USD?: {
3086
+ fair: number;
3087
+ loaded: number;
3088
+ /** @description Weighted-average tier risk multiplier applied across spots in this currency (1.0 when no sub-spot). */
3089
+ tierMultiplierWeightedAvg: number;
3090
+ };
3091
+ GBP?: {
3092
+ fair: number;
3093
+ loaded: number;
3094
+ /** @description Weighted-average tier risk multiplier applied across spots in this currency (1.0 when no sub-spot). */
3095
+ tierMultiplierWeightedAvg: number;
3096
+ };
3097
+ CHF?: {
3098
+ fair: number;
3099
+ loaded: number;
3100
+ /** @description Weighted-average tier risk multiplier applied across spots in this currency (1.0 when no sub-spot). */
3101
+ tierMultiplierWeightedAvg: number;
3102
+ };
3103
+ };
3104
+ loadingFactor: number;
3105
+ };
3106
+ modelConfidence: number;
3107
+ /** @enum {string} */
3108
+ advisoryLevel: "high_confidence" | "moderate_confidence" | "low_confidence";
3109
+ issuable: boolean;
3110
+ notes: string[];
3111
+ /** @description HistoricalScoreDistribution — object for single spot, array for portfolio. */
3112
+ underlying: {
3113
+ [key: string]: unknown;
3114
+ } | {
3115
+ [key: string]: unknown;
3116
+ }[];
3117
+ /**
3118
+ * Format: uuid
3119
+ * @description Present when the policy store is wired — pass to /v1/underwriting/policy/bind to bind this quote.
3120
+ */
3121
+ quoteId?: string;
3122
+ /**
3123
+ * Format: date-time
3124
+ * @description ISO timestamp after which the quote can no longer be bound.
3125
+ */
3126
+ expiresAt?: string;
3127
+ /**
3128
+ * Format: uuid
3129
+ * @description Present on GET after the quote has been bound — the resulting policy id.
3130
+ */
3131
+ boundPolicyId?: string;
3132
+ } & {
3133
+ [key: string]: unknown;
3134
+ };
3135
+ /** @enum {string} */
3136
+ WebhookEvent: "outcome.created" | "drift.fired" | "drift.resolved" | "calibration.completed" | "billing.subscription_updated" | "recommendation.completed" | "underwriting.policy.bound" | "underwriting.policy.triggered" | "underwriting.policy.settled";
2086
3137
  };
2087
3138
  responses: never;
2088
3139
  parameters: never;