{
  "openapi": "3.1.0",
  "info": {
    "title": "PerceptFolio public record",
    "version": "1.0.0",
    "description": "The terminal's own weekly verdict on 50 large US companies, graded against the S&P 500. Read-only, no key. Not investment advice."
  },
  "servers": [{ "url": "https://crimson-hat-6ad9.northbridgeai1.workers.dev" }],
  "paths": {
    "/house": {
      "get": {
        "operationId": "getPublicRecord",
        "summary": "Every weekly verdict, its grades and the hash chain",
        "responses": {
          "200": {
            "description": "The whole record. Cached for two minutes.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Record" } } }
          },
          "429": { "description": "More than 60 requests in a minute." }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Record": {
        "type": "object",
        "required": ["fixed", "list", "horizons", "engine", "feed", "calls", "marks", "chain", "at"],
        "properties": {
          "fixed": { "type": "string", "format": "date", "description": "The day the company list was fixed." },
          "list": { "type": "array", "items": { "type": "string" }, "description": "The 50 tickers." },
          "horizons": { "type": "array", "items": { "type": "integer" }, "description": "Days after a call at which it is graded." },
          "engine": { "type": "string", "description": "Scoring engine version." },
          "feed": { "type": "string", "description": "Price source." },
          "calls": { "type": "array", "items": { "$ref": "#/components/schemas/Call" } },
          "marks": {
            "type": "object",
            "description": "Grades by call id, then by horizon in days. Empty until a horizon passes.",
            "additionalProperties": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/Mark" } }
          },
          "chain": { "type": "array", "items": { "$ref": "#/components/schemas/Link" } },
          "batch": {
            "type": ["object", "null"],
            "description": "This week's batch, while or after it runs.",
            "properties": { "week": { "type": "string", "format": "date" }, "scored": { "type": "integer" }, "of": { "type": "integer" }, "done": { "type": "boolean" } }
          },
          "at": { "type": "integer", "description": "Server time, milliseconds since the epoch." }
        }
      },
      "Call": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "description": "<week>:<ticker>" },
          "week": { "type": "string", "format": "date", "description": "Monday of the batch." },
          "sym": { "type": "string" },
          "ts": { "type": "integer", "description": "Server time of the call, milliseconds since the epoch." },
          "verdict": { "type": "string", "enum": ["buy", "hold", "sell", "none"], "description": "none means not scored; see error." },
          "label": { "type": "string" },
          "score": { "type": ["number", "null"] },
          "confidence": { "type": ["number", "null"] },
          "price": { "type": ["number", "null"], "description": "Last close when the call was made." },
          "priceDate": { "type": ["string", "null"], "format": "date" },
          "spy": { "type": "number", "description": "SPY close beside it." },
          "spyDate": { "type": "string", "format": "date" },
          "error": { "type": ["string", "null"] }
        }
      },
      "Mark": {
        "type": "object",
        "properties": {
          "price": { "type": "number" },
          "spy": { "type": "number" },
          "date": { "type": "string", "format": "date" }
        }
      },
      "Link": {
        "type": "object",
        "properties": {
          "week": { "type": "string", "format": "date" },
          "n": { "type": "integer", "description": "Calls in the batch." },
          "head": { "type": "string", "description": "SHA-256 over the previous head and the batch's rows." },
          "at": { "type": "integer" }
        }
      }
    }
  }
}
