Counterfactual analysis of a score
"What's holding the verdict down?", "If wind picked up 3 knots, would we go?", "Is there a better window today?", "Is a nearby spot better?". One endpoint, four answers, pure math (no LLM in the analytical blocks).
Any authenticated plan. The four analytical blocks below are available on Free and up; the math typically runs in tens of milliseconds (the engine directly probes per-dimension perturbations without re-fetching weather, plus one extra provider fetch for the 24h window scan). The optional natural_language block also works on any plan, but needs your own Anthropic key set; with no key, natural_language.degraded_mode: true and a deterministic template stands in for a generated sentence.
What it answers
Four analyses returned in a single response:
binding_constraint: which dimension is dragging the verdict down hardest.marginal_sensitivities: ∂score/∂metric for the top-5 dimensions, so you can answer "by how much does X need to change to flip the verdict?".best_window_24h: hourly scan over a ±12h window, returning the single best-scoring hour + its top-3 explanatory drivers (null if nothing beats the baseline meaningfully).best_nearby_spots: sub-spots within radius re-scored against the same request (baseline excluded by slug).
Request
Unlike the intelligence endpoints, this one re-runs the baseline score itself: there's no session_id / scoreResult passthrough. You always send activity + spot + window; the four analytical blocks are opt-out (default on) via a nested include object, not a string array:
{
"activity": "kitesurfing",
"spot": { "lat": 36.013, "lng": -5.604 },
"window": { "from": "2026-07-04T09:00:00Z", "to": "2026-07-04T18:00:00Z" },
"include": {
"binding_constraint": true,
"marginal_sensitivities": true,
"best_window_24h": true,
"best_nearby_spot_km": 25,
"natural_language": true
}
}Every key in include is optional and defaults to true (50km for best_nearby_spot_km, capped at 200km) except natural_language, which defaults to false; set it explicitly to opt into the LLM block.
binding_constraint
Drag analysis on the dimension level: which dimension, if it alone moved to its optimal value, would lift the score the most. The result carries the dimension name + metric, its current contribution, the drag_pts it's costing, the would_become_score if it moved to optimum, and a limiting_class tag (wind / wave / thermal / visibility / precipitation / hard_gate / other). Useful for UI copy like "wind is OK but waves are the blocker, try after 3pm when the swell drops".
marginal_sensitivities
Numerical Jacobian: for each dimension, the engine perturbs the underlying metric by ±σ and ±2σ and observes the resulting score_delta. Each entry carries name, metric, current_value, weight, current_contribution, the per-perturbation array, and local_slope_per_unit, the least-squares slope ∂score/∂metric. Use for: "by how much does the wind need to increase to push us from marginal to favorable?".
best_window_24h
Hourly scan over a ±12h window around the request's midpoint (24h total, clipped to whatever horizon the provider actually returns), scoring each hour with the same activity profile. Returns the single best time + score + score_delta_vs_request, with the top-3 drivers that explain the lift over the baseline. Null when the provider fetch fails or returns too few samples.
best_nearby_spots
Finds sub-spots within include.best_nearby_spot_km (max 200km) via the spatial resolver's R-tree, re-scores each against the same baseline conditions, excludes the baseline spot by slug (so the source spot doesn't appear twice), drops any candidate that isn't at least 2 points better than the baseline, and returns up to the top 3 survivors sorted by lift, each with slug, score, score_delta_vs_request, distance_km, tier, and its top-3 drivers. Empty array when no spatial resolver is wired or nothing clears the bar.