openapi: 3.1.0
info:
    title: ForecastService API
    version: 1.0.0
paths:
    /api/forecast/v1/get-forecasts:
        get:
            tags:
                - ForecastService
            summary: GetForecasts
            operationId: GetForecasts
            parameters:
                - name: domain
                  in: query
                  required: false
                  schema:
                    type: string
                - name: region
                  in: query
                  required: false
                  schema:
                    type: string
            responses:
                "200":
                    description: Successful response
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/GetForecastsResponse'
                "400":
                    description: Validation error
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ValidationError'
                default:
                    description: Error response
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/Error'
    /api/forecast/v1/get-simulation-package:
        get:
            tags:
                - ForecastService
            summary: GetSimulationPackage
            operationId: GetSimulationPackage
            parameters:
                - name: runId
                  in: query
                  description: Currently ignored; always returns the latest package. Reserved for Phase 3 per-run lookup.
                  required: false
                  schema:
                    type: string
            responses:
                "200":
                    description: Successful response
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/GetSimulationPackageResponse'
                "400":
                    description: Validation error
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ValidationError'
                default:
                    description: Error response
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/Error'
    /api/forecast/v1/get-simulation-outcome:
        get:
            tags:
                - ForecastService
            summary: GetSimulationOutcome
            operationId: GetSimulationOutcome
            parameters:
                - name: runId
                  in: query
                  description: |-
                    IMPORTANT: Currently a no-op. Always returns the latest available outcome regardless of runId.
                     Per-run lookup is reserved for Phase 3. Check the response 'note' field when runId is supplied
                     and you need to detect a mismatch between requested and returned run.
                  required: false
                  schema:
                    type: string
            responses:
                "200":
                    description: Successful response
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/GetSimulationOutcomeResponse'
                "400":
                    description: Validation error
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ValidationError'
                default:
                    description: Error response
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/Error'
components:
    schemas:
        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.
        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.
        GetForecastsRequest:
            type: object
            properties:
                domain:
                    type: string
                region:
                    type: string
        GetForecastsResponse:
            type: object
            properties:
                forecasts:
                    type: array
                    items:
                        $ref: '#/components/schemas/Forecast'
                generatedAt:
                    type: integer
                    format: int64
                    description: 'Warning: Values > 2^53 may lose precision in JavaScript'
        Forecast:
            type: object
            properties:
                id:
                    type: string
                domain:
                    type: string
                region:
                    type: string
                title:
                    type: string
                scenario:
                    type: string
                feedSummary:
                    type: string
                probability:
                    type: number
                    format: double
                confidence:
                    type: number
                    format: double
                timeHorizon:
                    type: string
                signals:
                    type: array
                    items:
                        $ref: '#/components/schemas/ForecastSignal'
                cascades:
                    type: array
                    items:
                        $ref: '#/components/schemas/CascadeEffect'
                trend:
                    type: string
                priorProbability:
                    type: number
                    format: double
                calibration:
                    $ref: '#/components/schemas/CalibrationInfo'
                createdAt:
                    type: integer
                    format: int64
                    description: 'Warning: Values > 2^53 may lose precision in JavaScript'
                updatedAt:
                    type: integer
                    format: int64
                    description: 'Warning: Values > 2^53 may lose precision in JavaScript'
                perspectives:
                    $ref: '#/components/schemas/Perspectives'
                projections:
                    $ref: '#/components/schemas/Projections'
                caseFile:
                    $ref: '#/components/schemas/ForecastCase'
                simulationAdjustment:
                    type: number
                    format: double
                    description: |-
                        Simulation-scoring fields — populated when the deep forecast simulation pipeline
                         has run for this forecast's state and produced a non-zero adjustment.
                         simulation_adjustment: raw score delta (+0.08–+0.12 positive, -0.12/-0.15 negative).
                         sim_path_confidence: clamped [0,1] confidence of the matched sim top-path; 0 = not set.
                         demoted_by_simulation: true when a negative adjustment crossed the 0.50 acceptance threshold.
                simPathConfidence:
                    type: number
                    format: double
                demotedBySimulation:
                    type: boolean
        ForecastSignal:
            type: object
            properties:
                type:
                    type: string
                value:
                    type: string
                weight:
                    type: number
                    format: double
        CascadeEffect:
            type: object
            properties:
                domain:
                    type: string
                effect:
                    type: string
                probability:
                    type: number
                    format: double
        CalibrationInfo:
            type: object
            properties:
                marketTitle:
                    type: string
                marketPrice:
                    type: number
                    format: double
                drift:
                    type: number
                    format: double
                source:
                    type: string
        Perspectives:
            type: object
            properties:
                strategic:
                    type: string
                regional:
                    type: string
                contrarian:
                    type: string
        Projections:
            type: object
            properties:
                h24:
                    type: number
                    format: double
                d7:
                    type: number
                    format: double
                d30:
                    type: number
                    format: double
        ForecastCase:
            type: object
            properties:
                supportingEvidence:
                    type: array
                    items:
                        $ref: '#/components/schemas/ForecastCaseEvidence'
                counterEvidence:
                    type: array
                    items:
                        $ref: '#/components/schemas/ForecastCaseEvidence'
                triggers:
                    type: array
                    items:
                        type: string
                actorLenses:
                    type: array
                    items:
                        type: string
                baseCase:
                    type: string
                escalatoryCase:
                    type: string
                contrarianCase:
                    type: string
                changeSummary:
                    type: string
                changeItems:
                    type: array
                    items:
                        type: string
                actors:
                    type: array
                    items:
                        $ref: '#/components/schemas/ForecastActor'
                worldState:
                    $ref: '#/components/schemas/ForecastWorldState'
                branches:
                    type: array
                    items:
                        $ref: '#/components/schemas/ForecastBranch'
        ForecastCaseEvidence:
            type: object
            properties:
                type:
                    type: string
                summary:
                    type: string
                weight:
                    type: number
                    format: double
        ForecastActor:
            type: object
            properties:
                id:
                    type: string
                name:
                    type: string
                category:
                    type: string
                role:
                    type: string
                objectives:
                    type: array
                    items:
                        type: string
                constraints:
                    type: array
                    items:
                        type: string
                likelyActions:
                    type: array
                    items:
                        type: string
                influenceScore:
                    type: number
                    format: double
        ForecastWorldState:
            type: object
            properties:
                summary:
                    type: string
                activePressures:
                    type: array
                    items:
                        type: string
                stabilizers:
                    type: array
                    items:
                        type: string
                keyUnknowns:
                    type: array
                    items:
                        type: string
        ForecastBranch:
            type: object
            properties:
                kind:
                    type: string
                title:
                    type: string
                summary:
                    type: string
                outcome:
                    type: string
                projectedProbability:
                    type: number
                    format: double
                rounds:
                    type: array
                    items:
                        $ref: '#/components/schemas/ForecastBranchRound'
        ForecastBranchRound:
            type: object
            properties:
                round:
                    type: integer
                    format: int32
                focus:
                    type: string
                developments:
                    type: array
                    items:
                        type: string
                actorMoves:
                    type: array
                    items:
                        type: string
                probabilityShift:
                    type: number
                    format: double
        GetSimulationPackageRequest:
            type: object
            properties:
                runId:
                    type: string
                    description: Currently ignored; always returns the latest package. Reserved for Phase 3 per-run lookup.
        GetSimulationPackageResponse:
            type: object
            properties:
                found:
                    type: boolean
                runId:
                    type: string
                pkgKey:
                    type: string
                schemaVersion:
                    type: string
                theaterCount:
                    type: integer
                    format: int32
                generatedAt:
                    type: integer
                    format: int64
                    description: 'Unix timestamp in milliseconds (from Date.now()). Warning: Values > 2^53 may lose precision in JavaScript.. Warning: Values > 2^53 may lose precision in JavaScript'
                note:
                    type: string
                    description: |-
                        Populated when req.runId was supplied but does not match the returned package's runId.
                         Indicates that per-run filtering is not yet active and the latest package was returned instead.
                error:
                    type: string
                    description: |-
                        Populated when the Redis lookup failed. Distinguish from healthy not-found (found=false, error="").
                         Value: "redis_unavailable" on Redis errors.
        GetSimulationOutcomeRequest:
            type: object
            properties:
                runId:
                    type: string
                    description: |-
                        IMPORTANT: Currently a no-op. Always returns the latest available outcome regardless of runId.
                         Per-run lookup is reserved for Phase 3. Check the response 'note' field when runId is supplied
                         and you need to detect a mismatch between requested and returned run.
        GetSimulationOutcomeResponse:
            type: object
            properties:
                found:
                    type: boolean
                runId:
                    type: string
                outcomeKey:
                    type: string
                schemaVersion:
                    type: string
                theaterCount:
                    type: integer
                    format: int32
                generatedAt:
                    type: integer
                    format: int64
                    description: 'Unix timestamp in milliseconds (from Date.now()). Warning: Values > 2^53 may lose precision in JavaScript.. Warning: Values > 2^53 may lose precision in JavaScript'
                note:
                    type: string
                    description: |-
                        Populated when req.runId was supplied but does not match the returned outcome's runId.
                         Indicates that per-run filtering is not yet active and the latest outcome was returned instead.
                error:
                    type: string
                    description: |-
                        Populated when the Redis lookup failed. Distinguish from healthy not-found (found=false, error="").
                         Value: "redis_unavailable" on Redis errors.
                theaterSummariesJson:
                    type: string
                    description: |-
                        JSON-encoded array of theater summaries for the UI (populated when found=true).
                         Shape: Array<{ theaterId, theaterLabel, stateKind, topPaths: [{label, summary, confidence, keyActors}], dominantReactions, stabilizers, invalidators }>
                         Parse with JSON.parse() on the client. Empty string when found=false.
