Ctrl K
ComunidadGuías…

docs/api/ScenarioService.openapi.yaml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
openapi: 3.1.0
info:
    title: ScenarioService API
    version: 1.0.0
security:
    - WorldMonitorKey: []
    - ApiKeyHeader: []
servers:
    - url: https://api.worldmonitor.app
paths:
    /api/scenario/v1/run-scenario:
        post:
            parameters:
                - name: Idempotency-Key
                  in: header
                  description: Optional client-generated idempotency key. Retrying a POST with the same key and an identical request body replays the original response (only the status, body, and Content-Type are reproduced) instead of re-executing; reusing the key with a different body is rejected with 422. For mutations this avoids duplicating the side effect, while for batch-read POSTs it replays a cached snapshot that can be up to 24 hours stale. Keys are scoped per authenticated caller (falling back to the source IP for unauthenticated endpoints) and retained for 24 hours.
                  required: false
                  example: "4f8b9c2e-1a3d-4b6f-8e0a-2c5d7f9b1e34"
                  schema:
                    type: string
                    minLength: 1
                    maxLength: 255
                    pattern: "^[\\x21-\\x7E]{1,255}$"
            tags:
                - ScenarioService
            summary: RunScenario
            description: |-
                RunScenario enqueues a scenario job on scenario-queue:pending. PRO-gated.
                 Async job pattern: a successful enqueue returns HTTP 202 Accepted with a
                 Location header pointing at GetScenarioStatus; poll it (or the statusUrl
                 body field) with the returned jobId until status is "done" or "failed".
                 The scenario-worker (scripts/scenario-worker.mjs) pulls jobs off the
                 queue via BLMOVE and writes results under scenario-result:{job_id}. Requires entitlement tier >= 1.
            operationId: RunScenario
            security:
                - WorldMonitorKey: []
                - ApiKeyHeader: []
                - BearerAuth: []
            requestBody:
                content:
                    application/json:
                        example:
                            "disruptionPct": 1
                            "iso2": "US"
                            "scenarioId": "hormuz-tanker-blockade"
                        schema:
                            $ref: '#/components/schemas/RunScenarioRequest'
                required: true
            responses:
                "202":
                    description: Accepted — scenario job enqueued. The body carries the job id (jobId), the initial status (always pending) and a poll URL (statusUrl); the Location header points at the same GetScenarioStatus endpoint. Poll it until status is done or failed.
                    headers:
                        Idempotency-Key:
                            schema:
                                type: string
                            description: The idempotency key echoed from the request. Present only when the client opted into idempotency.
                        Idempotent-Replayed:
                            schema:
                                type: boolean
                            description: true when this response was replayed from an earlier request with the same key, false on the first (original) request. Present only when the client opted into idempotency.
                        Location:
                            schema:
                                type: string
                            description: Relative URL of the job-status poll endpoint for this job (same value as the statusUrl body field).
                            example: "/api/scenario/v1/get-scenario-status?jobId=scenario%3A1717200000000%3Aabcd1234"
                    content:
                        application/json:
                            example:
                                "jobId": "scenario:1717200000000:abcd1234"
                                "status": "pending"
                                "statusUrl": "/api/scenario/v1/get-scenario-status?jobId=scenario%3A1717200000000%3Aabcd1234"
                            schema:
                                $ref: '#/components/schemas/RunScenarioResponse'
                "400":
                    description: Validation error, invalid Idempotency-Key header, or malformed JSON request body
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/ValidationError'
                                    - type: object
                                      required:
                                        - error
                                        - message
                                      properties:
                                        error:
                                            type: string
                                        message:
                                            type: string
                                    - $ref: '#/components/schemas/InvalidRequestBodyError'
                "409":
                    description: A request with this Idempotency-Key is still being processed
                    headers:
                        Idempotency-Key:
                            schema:
                                type: string
                            description: The idempotency key supplied by the client.
                        Retry-After:
                            schema:
                                type: string
                            description: Seconds to wait before retrying the in-flight request.
                    content:
                        application/json:
                            schema:
                                type: object
                                required:
                                    - error
                                    - message
                                properties:
                                    error:
                                        type: string
                                    message:
                                        type: string
                "422":
                    description: The Idempotency-Key was already used with a different request body
                    headers:
                        Idempotency-Key:
                            schema:
                                type: string
                            description: The idempotency key supplied by the client.
                    content:
                        application/json:
                            schema:
                                type: object
                                required:
                                    - error
                                    - message
                                properties:
                                    error:
                                        type: string
                                    message:
                                        type: string
                "401":
                    description: Missing or invalid API key.
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/UnauthorizedError'
                "403":
                    description: PRO entitlement access denied.
                    headers:
                        X-Billing-Verification:
                            description: Present when the 403 is a billing-provider-confirmed subscription lapse (value subscription_lapsed, matching the body `code`).
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ForbiddenError'
                "429":
                    description: Rate limit exceeded.
                    headers:
                        X-RateLimit-Limit:
                            description: Maximum requests allowed in the active rate-limit window.
                            schema:
                                type: string
                        X-RateLimit-Remaining:
                            description: Requests remaining in the active rate-limit window.
                            schema:
                                type: string
                        X-RateLimit-Reset:
                            description: Unix epoch milliseconds when the active rate-limit window resets.
                            schema:
                                type: string
                        Retry-After:
                            description: Seconds to wait before retrying the request.
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/Error'
                                    - $ref: '#/components/schemas/RateLimitError'
                "503":
                    description: Service unavailable. Billing-verification responses include code and X-Billing-Verification; other gateway infrastructure failures use the generic GatewayError shape.
                    headers:
                        Retry-After:
                            description: Seconds to wait before retrying (1-60).
                            schema:
                                type: string
                        X-Billing-Verification:
                            description: Billing-verification state that produced this response (matches the body `code`).
                            schema:
                                type: string
                        X-Validation-Mode:
                            description: Present with value degraded when user API-key validation is temporarily unavailable.
                            schema:
                                type: string
                        X-RateLimit-Mode:
                            description: Present with value degraded when a fail-closed rate-limit dependency is unavailable.
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/BillingVerificationError'
                                    - $ref: '#/components/schemas/GatewayError'
                default:
                    description: Gateway or handler error response.
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/Error'
                                    - $ref: '#/components/schemas/GatewayError'
    /api/scenario/v1/get-scenario-status:
        get:
            tags:
                - ScenarioService
            summary: GetScenarioStatus
            description: |-
                GetScenarioStatus polls a single job's result. PRO-gated.
                 Returns status="pending" when no result key exists, mirroring the
                 worker's lifecycle state once the key is written. Requires entitlement tier >= 1.
            operationId: GetScenarioStatus
            security:
                - WorldMonitorKey: []
                - ApiKeyHeader: []
                - BearerAuth: []
            parameters:
                - name: jobId
                  in: query
                  description: |-
                    Job id of the form `scenario:{epoch_ms}:{32-hex}` (128-bit). The legacy
                     8-character suffix remains valid. Path-traversal guarded by JOB_ID_RE.
                  required: true
                  example: "scenario:1717200000000:abcd1234"
                  schema:
                    type: string
                    pattern: '^scenario:[0-9]{13}:([a-f0-9]{32}|[a-z0-9]{8})$'
                - name: jmespath
                  in: query
                  description: |-
                    Optional JMESPath expression applied server-side to project or reduce the JSON response before it is returned (mirrors the MCP jmespath argument). Invalid expressions, expressions larger than 1024 UTF-8 bytes, or projections that exceed the 256 KB output cap return HTTP 400 with a {_jmespath_error, original_keys} envelope. Grammar and worked examples: https://www.worldmonitor.app/docs/mcp-jmespath.
                  required: false
                  example: "keys(@)"
                  schema:
                    type: string
            responses:
                "200":
                    description: Successful response
                    content:
                        application/json:
                            example:
                                "result":
                                    "affectedChokepointIds":
                                        - "hormuz_strait"
                                    "template":
                                        "costShockMultiplier": 2.1
                                        "disruptionPct": 100
                                        "durationDays": 14
                                        "name": "hormuz_strait"
                                    "topImpactCountries":
                                        - "impactPct": 100
                                          "iso2": "US"
                                          "totalImpact": 42.5
                                "status": "done"
                            schema:
                                $ref: '#/components/schemas/GetScenarioStatusResponse'
                "400":
                    description: Validation error
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/ValidationError'
                                    - $ref: '#/components/schemas/JmespathProjectionError'
                "401":
                    description: Missing or invalid API key.
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/UnauthorizedError'
                "403":
                    description: PRO entitlement access denied.
                    headers:
                        X-Billing-Verification:
                            description: Present when the 403 is a billing-provider-confirmed subscription lapse (value subscription_lapsed, matching the body `code`).
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ForbiddenError'
                "429":
                    description: Rate limit exceeded.
                    headers:
                        X-RateLimit-Limit:
                            description: Maximum requests allowed in the active rate-limit window.
                            schema:
                                type: string
                        X-RateLimit-Remaining:
                            description: Requests remaining in the active rate-limit window.
                            schema:
                                type: string
                        X-RateLimit-Reset:
                            description: Unix epoch milliseconds when the active rate-limit window resets.
                            schema:
                                type: string
                        Retry-After:
                            description: Seconds to wait before retrying the request.
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/Error'
                                    - $ref: '#/components/schemas/RateLimitError'
                "503":
                    description: Service unavailable. Billing-verification responses include code and X-Billing-Verification; other gateway infrastructure failures use the generic GatewayError shape.
                    headers:
                        Retry-After:
                            description: Seconds to wait before retrying (1-60).
                            schema:
                                type: string
                        X-Billing-Verification:
                            description: Billing-verification state that produced this response (matches the body `code`).
                            schema:
                                type: string
                        X-Validation-Mode:
                            description: Present with value degraded when user API-key validation is temporarily unavailable.
                            schema:
                                type: string
                        X-RateLimit-Mode:
                            description: Present with value degraded when a fail-closed rate-limit dependency is unavailable.
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/BillingVerificationError'
                                    - $ref: '#/components/schemas/GatewayError'
                default:
                    description: Gateway or handler error response.
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/Error'
                                    - $ref: '#/components/schemas/GatewayError'
    /api/scenario/v1/list-scenario-templates:
        get:
            tags:
                - ScenarioService
            summary: ListScenarioTemplates
            description: |-
                ListScenarioTemplates returns the catalog of pre-defined scenarios.
                 Not PRO-gated — used by documented public API consumers.
            operationId: ListScenarioTemplates
            parameters:
                - name: jmespath
                  in: query
                  description: |-
                    Optional JMESPath expression applied server-side to project or reduce the JSON response before it is returned (mirrors the MCP jmespath argument). Invalid expressions, expressions larger than 1024 UTF-8 bytes, or projections that exceed the 256 KB output cap return HTTP 400 with a {_jmespath_error, original_keys} envelope. Grammar and worked examples: https://www.worldmonitor.app/docs/mcp-jmespath.
                  required: false
                  example: "keys(@)"
                  schema:
                    type: string
            responses:
                "200":
                    description: Successful response
                    content:
                        application/json:
                            example:
                                "templates":
                                    - "affectedChokepointIds":
                                        - "suez"
                                      "affectedHs2":
                                          - "27"
                                      "costShockMultiplier": 75.25
                                      "disruptionPct": 1
                                      "durationDays": 7
                            schema:
                                $ref: '#/components/schemas/ListScenarioTemplatesResponse'
                "400":
                    description: Validation error
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/ValidationError'
                                    - $ref: '#/components/schemas/JmespathProjectionError'
                "401":
                    description: Missing or invalid API key.
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/UnauthorizedError'
                "403":
                    description: API access requires an active subscription (the API key's subscription is inactive or expired).
                    headers:
                        X-Billing-Verification:
                            description: Present when the 403 is a billing-provider-confirmed subscription lapse (value subscription_lapsed, matching the body `code`).
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ForbiddenError'
                "429":
                    description: Rate limit exceeded.
                    headers:
                        X-RateLimit-Limit:
                            description: Maximum requests allowed in the active rate-limit window.
                            schema:
                                type: string
                        X-RateLimit-Remaining:
                            description: Requests remaining in the active rate-limit window.
                            schema:
                                type: string
                        X-RateLimit-Reset:
                            description: Unix epoch milliseconds when the active rate-limit window resets.
                            schema:
                                type: string
                        Retry-After:
                            description: Seconds to wait before retrying the request.
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/Error'
                                    - $ref: '#/components/schemas/RateLimitError'
                "503":
                    description: Service unavailable. Billing-verification responses include code and X-Billing-Verification; other gateway infrastructure failures use the generic GatewayError shape.
                    headers:
                        Retry-After:
                            description: Seconds to wait before retrying (1-60).
                            schema:
                                type: string
                        X-Billing-Verification:
                            description: Billing-verification state that produced this response (matches the body `code`).
                            schema:
                                type: string
                        X-Validation-Mode:
                            description: Present with value degraded when user API-key validation is temporarily unavailable.
                            schema:
                                type: string
                        X-RateLimit-Mode:
                            description: Present with value degraded when a fail-closed rate-limit dependency is unavailable.
                            schema:
                                type: string
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/BillingVerificationError'
                                    - $ref: '#/components/schemas/GatewayError'
                default:
                    description: Gateway or handler error response.
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/Error'
                                    - $ref: '#/components/schemas/GatewayError'
components:
    securitySchemes:
        WorldMonitorKey:
            type: apiKey
            in: header
            name: X-WorldMonitor-Key
            description: User-issued WorldMonitor API key.
        ApiKeyHeader:
            type: apiKey
            in: header
            name: X-Api-Key
            description: Alias header for the WorldMonitor API key (X-WorldMonitor-Key).
        BearerAuth:
            type: http
            scheme: bearer
            description: 'Bearer token: a Clerk-issued JWT for browser session flows, passed as Authorization: Bearer <token>.'
    schemas:
        JmespathProjectionError:
            description: Returned when a REST jmespath projection is invalid or exceeds the expression/output byte limits.
            properties:
                _jmespath_error:
                    description: Projection error discriminator and details.
                    type: string
                original_keys:
                    description: Top-level keys or shape of the unprojected response.
                    items:
                        type: string
                    type: array
            required:
                - _jmespath_error
                - original_keys
            type: object
        UnauthorizedError:
            type: object
            properties:
                error:
                    type: string
                    description: Human-readable error message.
            required:
                - error
            description: Returned when the API key is missing, malformed, or lacks current API access.
        Error:
            type: object
            properties:
                message:
                    type: string
                    description: Error message (e.g., 'user not found', 'database connection failed')
            description: Error is returned when a handler encounters an error. It contains a simple error message that the developer can customize.
        BillingVerificationError:
            type: object
            description: "Returned with HTTP 503 when paid access cannot be confirmed right now: the billing provider is re-verifying a recently expired subscription, or the entitlement backend is unreachable. Retryable — honor Retry-After."
            properties:
                error:
                    type: string
                    description: Human-readable billing-verification failure reason.
                code:
                    type: string
                    enum:
                        - renewal_verification_pending
                        - renewal_verification_failed
                        - entitlement_verification_unavailable
                    description: Machine-readable billing-verification state, mirrored in the X-Billing-Verification response header.
                requiredTier:
                    type: integer
                    format: int32
                    description: Minimum entitlement tier required for this endpoint, when the denial came from a tier gate.
            required:
                - error
                - code
        InvalidRequestBodyError:
            type: object
            description: Returned when a JSON POST request body is empty or malformed.
            properties:
                message:
                    type: string
                    description: Invalid request body
            required:
                - message
        GatewayError:
            type: object
            description: Returned by gateway infrastructure errors before an RPC handler runs, such as origin, routing, method, authentication, or quota checks.
            properties:
                error:
                    oneOf:
                        - type: string
                        - type: object
                          additionalProperties: true
                    description: Gateway error reason or structured gateway failure details.
            required:
                - error
        RateLimitError:
            type: object
            description: Returned when a gateway or handler rate limit rejects the request.
            properties:
                error:
                    type: string
                    description: Human-readable rate-limit failure reason.
            required:
                - error
        ForbiddenError:
            type: object
            properties:
                error:
                    type: string
                    description: Human-readable entitlement failure reason.
                code:
                    type: string
                    enum:
                        - subscription_lapsed
                    description: Machine-readable denial code, present when the 403 is a billing-provider-confirmed subscription lapse (mirrored in the X-Billing-Verification response header).
                requiredTier:
                    type: integer
                    format: int32
                    description: Minimum entitlement tier required for this endpoint.
                currentTier:
                    type: integer
                    format: int32
                    description: Caller entitlement tier when known.
                planKey:
                    type: string
                    description: Caller plan key when known.
            required:
                - error
            description: Returned when a PRO-gated endpoint denies access because the caller has no resolved authenticated user, entitlements cannot be verified, or the caller lacks the required entitlement tier.
        FieldViolation:
            type: object
            properties:
                field:
                    type: string
                    description: The field path that failed validation (e.g., 'user.email' for nested fields). For header validation, this will be the header name (e.g., 'X-API-Key')
                description:
                    type: string
                    description: Human-readable description of the validation violation (e.g., 'must be a valid email address', 'required field missing')
            required:
                - field
                - description
            description: FieldViolation describes a single validation error for a specific field.
        ValidationError:
            type: object
            properties:
                violations:
                    type: array
                    items:
                        $ref: '#/components/schemas/FieldViolation'
                    description: List of validation violations
            required:
                - violations
            description: ValidationError is returned when request validation fails. It contains a list of field violations describing what went wrong.
        RunScenarioRequest:
            type: object
            properties:
                scenarioId:
                    type: string
                    maxLength: 128
                    minLength: 1
                    description: Scenario template id — must match an entry in SCENARIO_TEMPLATES.
                iso2:
                    type: string
                    pattern: ^([A-Z]{2})?$
                    description: |-
                        Optional 2-letter ISO country code to scope the impact computation.
                         When absent, use the bounded country/sector manifest in existing seed metadata.
                         Missing or old manifest means unknown coverage.
                disruptionPct:
                    type: integer
                    maximum: 100
                    minimum: 0
                    format: int32
                    description: Physical scenarios only. Omitted preserves the template default; zero is valid.
            required:
                - scenarioId
            description: |-
                RunScenarioRequest enqueues a scenario job on the scenario-queue:pending
                 Upstash list for the async scenario-worker to pick up.
        RunScenarioResponse:
            type: object
            properties:
                jobId:
                    type: string
                    description: Generated job id of the form `scenario:{epoch_ms}:{8-char-suffix}`.
                status:
                    type: string
                    description: Always "pending" at enqueue time.
                statusUrl:
                    type: string
                    description: |-
                        Convenience URL the caller can use to poll this job's status.
                         Server-computed as `/api/scenario/v1/get-scenario-status?jobId=<job_id>`.
                         Restored after the v1 → v1 sebuf migration because external callers
                         may key off this field.
            description: |-
                RunScenarioResponse carries the enqueued job id. Clients poll
                 GetScenarioStatus with this id until status is "done" or "failed". A successful
                 enqueue returns HTTP 202 Accepted with a Location header pointing at
                 GetScenarioStatus; treat any 2xx as success.
        GetScenarioStatusRequest:
            type: object
            properties:
                jobId:
                    type: string
                    pattern: ^scenario:[0-9]{13}:([a-f0-9]{32}|[a-z0-9]{8})$
                    description: |-
                        Job id of the form `scenario:{epoch_ms}:{32-hex}` (128-bit). The legacy
                         8-character suffix remains valid. Path-traversal guarded by JOB_ID_RE.
            required:
                - jobId
            description: GetScenarioStatusRequest polls the worker result for an enqueued job id.
        GetScenarioStatusResponse:
            type: object
            properties:
                status:
                    type: string
                result:
                    $ref: '#/components/schemas/ScenarioResult'
                error:
                    type: string
                    description: Populated only when status == "failed".
            description: |-
                GetScenarioStatusResponse reflects the worker's lifecycle state.
                 "pending" — no key yet (job still queued or very-recent enqueue).
                 "processing" — worker has claimed the job but hasn't completed compute.
                 "done" — compute succeeded; `result` is populated.
                 "failed" — compute errored; `error` is populated.
        ScenarioResult:
            type: object
            properties:
                affectedChokepointIds:
                    type: array
                    items:
                        type: string
                        description: Chokepoint ids disrupted by this scenario.
                topImpactCountries:
                    type: array
                    items:
                        $ref: '#/components/schemas/ScenarioImpactCountry'
                template:
                    $ref: '#/components/schemas/ScenarioResultTemplate'
                scenarioId:
                    type: string
                    description: Selected catalog template identifier.
                scopedIso2:
                    type: string
                    description: Empty means all countries in the manifest.
                coverage:
                    $ref: '#/components/schemas/ScenarioCoverage'
                computedAt:
                    type: string
                    description: Computation time, not source observation time.
            description: |-
                ScenarioResult is the computed payload the scenario-worker writes back
                 under the `scenario-result:{job_id}` Redis key. Populated only when
                 GetScenarioStatusResponse.status == "done".
        ScenarioImpactCountry:
            type: object
            properties:
                iso2:
                    type: string
                    description: 2-letter ISO country code.
                totalImpact:
                    type: number
                    format: double
                    description: |-
                        Raw weighted impact value aggregated across the country's exposed HS2
                         chapters. Physical scenarios use exposureScore * (disruption_pct / 100)
                         * cost_shock_multiplier; tariff-shock scenarios use vulnerabilityIndex
                         * cost_shock_multiplier. Relative-only - not a currency amount.
                impactPct:
                    type: integer
                    format: int32
                    description: |-
                        Impact as a 0-100 share of max(maxReturnedTotalImpact, 1), capped at 100.
                         Because of the denominator floor, the top country can be below 100 when
                         all returned totalImpact values are below 1.
                evaluatedRecords:
                    type: integer
                    format: int32
                    description: Country/sector records that actually produced total_impact.
                requestedRecords:
                    type: integer
                    format: int32
                    description: Country/sector records requested for this country.
                partialEvidence:
                    type: boolean
                    description: |-
                        True when evaluated_records < requested_records. total_impact is then a LOWER
                         BOUND over the evidence that was available, not the country's impact, and must
                         not be read as low exposure.
            description: ScenarioImpactCountry carries a single country's relative scenario impact score.
        ScenarioResultTemplate:
            type: object
            properties:
                name:
                    type: string
                    description: |-
                        Worker-derived template key, not a display name. Physical scenarios join
                         affected_chokepoint_ids with `+`; tariff-type scenarios may use
                         `tariff_shock` when no physical chokepoint is affected.
                disruptionPct:
                    type: integer
                    format: int32
                    description: |-
                        0-100 percent of chokepoint capacity blocked. The EFFECTIVE severity: the
                         caller's RunScenarioRequest.disruption_pct when supplied, else the registry default.
                durationDays:
                    type: integer
                    format: int32
                    description: Descriptive duration in days; not an input to the impact calculation.
                costShockMultiplier:
                    type: number
                    format: double
                    description: Freight cost multiplier applied on top of bypass corridor costs.
            description: |-
                ScenarioResultTemplate carries the EFFECTIVE run parameters, so clients can render
                 them without re-looking up the template registry. All fields except disruption_pct
                 are registry values; disruption_pct is the caller's override when one was supplied.
        ScenarioCoverage:
            type: object
            properties:
                status:
                    type: string
                    description: complete, partial, or unknown. Complete refers to the bounded manifest only.
                countryIds:
                    type: array
                    items:
                        type: string
                        description: 'Requested countries: one selected country or the manifest country universe.'
                hs2Codes:
                    type: array
                    items:
                        type: string
                        description: Requested template chapters, or manifest chapters for all-sector templates.
                records:
                    type: array
                    items:
                        $ref: '#/components/schemas/ScenarioCoverageRecord'
                manifestFetchedAt:
                    type: string
                    description: Seed metadata production time, not trade observation time.
        ScenarioCoverageRecord:
            type: object
            properties:
                iso2:
                    type: string
                    description: Requested 2-letter ISO country code; paired with hs2 as the record reference.
                hs2:
                    type: string
                    description: Requested 2-digit HS chapter; paired with iso2 as the record reference.
                state:
                    type: string
                    description: |-
                        evaluated, missing, malformed, incomplete_routes, or not_seeded.
                         incomplete_routes means the cached record was well-formed but did not carry an
                         entry for every chokepoint this scenario disrupts — seeder/template registry
                         drift, NOT corrupt cache data.
                basis:
                    type: string
                    description: flow_weighted or country_route_fallback, only for evaluated records.
                rawImpact:
                    type: number
                    format: double
                    description: Relative score units, not currency. Present only for evaluated records.
                fetchedAt:
                    type: string
                    description: Cache production time. Observation date is unknown unless separately supplied.
            description: One requested country/sector record. Missing evidence never implies zero impact.
        ListScenarioTemplatesRequest:
            type: object
        ListScenarioTemplatesResponse:
            type: object
            properties:
                templates:
                    type: array
                    items:
                        $ref: '#/components/schemas/ScenarioTemplate'
        ScenarioTemplate:
            type: object
            properties:
                id:
                    type: string
                name:
                    type: string
                affectedChokepointIds:
                    type: array
                    items:
                        type: string
                        description: |-
                            Chokepoint ids this scenario disrupts. Empty for tariff-shock scenarios
                             that have no physical chokepoint closure.
                disruptionPct:
                    type: integer
                    format: int32
                    description: 0-100 percent of chokepoint capacity blocked.
                durationDays:
                    type: integer
                    format: int32
                    description: Estimated duration of disruption in days.
                affectedHs2:
                    type: array
                    items:
                        type: string
                        description: HS2 chapter codes affected. Empty means ALL sectors are affected.
                costShockMultiplier:
                    type: number
                    format: double
                    description: Freight cost multiplier applied on top of bypass corridor costs.
            description: |-
                ScenarioTemplate mirrors the catalog shape served by
                 GET /api/scenario/v1/list-scenario-templates. The authoritative template
                 registry lives in server/worldmonitor/supply-chain/v1/scenario-templates.ts.