openapi: 3.1.0
info:
  title: PAIL Evidence Runtime API
  version: 2.0.0
  description: Public synthetic evaluators and the authenticated ten-query evidence trial. The private PAIL rule implementation is not exposed by this API.
servers:
  - url: https://ancient-intelligence-lab.kakarotvira06.workers.dev
paths:
  /api/health:
    get:
      operationId: getHealth
      responses:
        "200": {description: Public bindings and optional private-runtime availability}
  /api/evaluate/rag:
    post:
      operationId: evaluateSyntheticRagEvidence
      description: Runs the bounded no-LLM exact-anchor evaluator on synthetic JSON.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [anchor_field, anchor_value, records]
              properties:
                anchor_field: {type: string, maxLength: 64}
                anchor_value: {type: string, maxLength: 256}
                records: {$ref: "#/components/schemas/Records"}
      responses:
        "200": {description: Bounded evaluator decision}
        "400": {$ref: "#/components/responses/Error"}
        "429": {$ref: "#/components/responses/Error"}
  /api/evaluate/rca:
    post:
      operationId: evaluateSyntheticRcaTrace
      description: Isolates and orders one submitted synthetic trace without claiming causal proof.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [trace_id, records]
              properties:
                trace_id: {type: string, maxLength: 256}
                records: {$ref: "#/components/schemas/Records"}
      responses:
        "200": {description: Bounded RCA view}
        "400": {$ref: "#/components/responses/Error"}
  /api/auth/request-link:
    post:
      operationId: requestTrialLink
      description: Sends a 15-minute sign-in link after IP and email rate limits.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties: {email: {type: string, format: email}}
      responses:
        "202": {description: Link accepted for delivery}
        "429": {$ref: "#/components/responses/Error"}
        "503": {$ref: "#/components/responses/Error"}
  /api/auth/verify:
    get:
      operationId: verifyTrialLink
      parameters:
        - in: query
          name: token
          required: true
          schema: {type: string}
      responses:
        "302": {description: Secure session cookie issued and browser redirected}
        "400": {$ref: "#/components/responses/Error"}
  /api/auth/logout:
    post:
      operationId: logoutTrial
      security: [{cookieAuth: []}]
      responses:
        "204": {description: Session removed}
  /api/sandbox/status:
    get:
      operationId: getTrialStatus
      security: [{cookieAuth: []}, {bearerAuth: []}]
      responses:
        "200": {description: Quota, corpus, expiry, and service state}
        "401": {$ref: "#/components/responses/Error"}
  /api/sandbox/upload:
    post:
      operationId: uploadTrialCorpus
      description: Forwards 1-5 sanitized files, at most 5 MB total, to the tenant-isolated private runtime. A corpus expires within 24 hours.
      security: [{cookieAuth: []}, {bearerAuth: []}]
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [files]
              properties:
                files:
                  type: array
                  minItems: 1
                  maxItems: 5
                  items: {type: string, format: binary}
      responses:
        "201": {description: Isolated corpus created}
        "400": {$ref: "#/components/responses/Error"}
        "401": {$ref: "#/components/responses/Error"}
        "413": {$ref: "#/components/responses/Error"}
        "415": {$ref: "#/components/responses/Error"}
        "503": {$ref: "#/components/responses/Error"}
  /api/sandbox/query:
    post:
      operationId: queryTrialCorpus
      description: Reserves one of ten account queries, calls the private evidence runtime, and optionally asks Workers AI to narrate only released evidence. Conflicts and missing evidence fail closed.
      security: [{cookieAuth: []}, {bearerAuth: []}]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [query, corpus_id]
              properties:
                query: {type: string, minLength: 1, maxLength: 4096}
                corpus_id: {type: string, pattern: "^[a-f0-9]{32}$"}
                limit: {type: integer, minimum: 1, maximum: 10, default: 5}
      responses:
        "200":
          description: VERIFIED_PACKET_READY, ANSWER_FROM_VERIFIED_EVIDENCE, CONFLICT_WITHHELD, or NO_VERIFIED_EVIDENCE
        "401": {$ref: "#/components/responses/Error"}
        "403": {$ref: "#/components/responses/Error"}
        "409": {$ref: "#/components/responses/Error"}
        "429": {$ref: "#/components/responses/Error"}
        "503": {$ref: "#/components/responses/Error"}
  /api/sandbox/corpus:
    delete:
      operationId: deleteTrialCorpus
      security: [{cookieAuth: []}, {bearerAuth: []}]
      responses:
        "200": {description: Tenant corpus deleted or no active corpus}
        "401": {$ref: "#/components/responses/Error"}
        "502": {$ref: "#/components/responses/Error"}
  /api/sandbox/runs:
    get:
      operationId: listTrialRunSummaries
      security: [{cookieAuth: []}, {bearerAuth: []}]
      responses:
        "200": {description: Bounded run summaries; no raw query text}
    delete:
      operationId: deleteTrialRunSummaries
      security: [{cookieAuth: []}, {bearerAuth: []}]
      responses:
        "200": {description: All tenant run summaries deleted}
components:
  securitySchemes:
    cookieAuth: {type: apiKey, in: cookie, name: pail_session}
    bearerAuth: {type: http, scheme: bearer}
  schemas:
    Records:
      type: array
      minItems: 1
      maxItems: 50
      items:
        type: object
        additionalProperties: true
    Error:
      type: object
      required: [error]
      properties:
        error: {type: string}
  responses:
    Error:
      description: Explicit bounded error
      content:
        application/json:
          schema: {$ref: "#/components/schemas/Error"}
