{
"id": "app.matakite.forecast",
"defs": {
"main": {
"key": "tid",
"type": "record",
"record": {
"type": "object",
"required": [
"subject",
"probability",
"createdAt"
],
"properties": {
"date": {
"ref": "#dateForecast",
"type": "ref",
"description": "Point and optional quantile forecast for a date question."
},
"multi": {
"ref": "#multiForecast",
"type": "ref",
"description": "Probability mass for a multi question. Appviews require one entry per question option id, unique ids, and a total of 100."
},
"numeric": {
"ref": "#numericForecast",
"type": "ref",
"description": "Point and optional quantile forecast for a numeric question."
},
"subject": {
"ref": "com.atproto.repo.strongRef",
"type": "ref",
"description": "The question being forecast (uri + cid). The cid pins the exact question version this forecast was made against."
},
"createdAt": {
"type": "string",
"format": "datetime"
},
"rationale": {
"type": "string",
"maxLength": 3000,
"description": "Optional short reasoning. Public, attached to the forecaster's track record.",
"maxGraphemes": 300
},
"probability": {
"type": "integer",
"maximum": 100,
"minimum": 0,
"description": "Percent probability of YES for binary questions. 0 and 100 are permitted but brave. Integer by design (matches Metaculus/Manifold/Kalshi UX; calibration math is fine at integer precision; nuance lives in the forecast trail over time, not in a single value). If extreme-tail precision is ever needed, add an optional logOdds field; do not change this one. The field remains required for Lexicon evolution compatibility. Writers of multi, numeric, and date forecasts MUST set it to 50; appviews MUST ignore it when a typed payload is present. See docs/lexicon-evolution.md."
}
}
},
"description": "A forecast on a binary, multi, numeric, or date question. Revisions are new records with the same subject uri; the full trail is retained and used for time-weighted scoring. Appviews select the payload matching the cid-pinned question type and reject records with conflicting typed payloads."
},
"dateForecast": {
"type": "object",
"required": [
"point"
],
"properties": {
"point": {
"type": "string",
"format": "datetime",
"description": "UTC datetime point estimate. Appviews validate it against the question's date bounds."
},
"quantiles": {
"type": "array",
"items": {
"ref": "#dateQuantile",
"type": "ref"
},
"maxLength": 99,
"description": "Optional uncertainty distribution. Appviews require unique ascending levels and nondecreasing datetimes."
}
}
},
"dateQuantile": {
"type": "object",
"required": [
"level",
"value"
],
"properties": {
"level": {
"type": "integer",
"maximum": 99,
"minimum": 1,
"description": "Percentile level, for example 10, 50, or 90."
},
"value": {
"type": "string",
"format": "datetime",
"description": "UTC datetime at this percentile."
}
}
},
"multiForecast": {
"type": "object",
"required": [
"probabilities"
],
"properties": {
"probabilities": {
"type": "array",
"items": {
"ref": "#optionProbability",
"type": "ref"
},
"maxLength": 50,
"minLength": 2,
"description": "Probability mass by stable option id. Entries sum to 100 under reference appview policy."
}
}
},
"numericForecast": {
"type": "object",
"required": [
"point"
],
"properties": {
"point": {
"type": "string",
"description": "Decimal-string point estimate. Appviews validate it against the question's numeric bounds."
},
"quantiles": {
"type": "array",
"items": {
"ref": "#numericQuantile",
"type": "ref"
},
"maxLength": 99,
"description": "Optional uncertainty distribution. Appviews require unique ascending levels and nondecreasing values."
}
}
},
"numericQuantile": {
"type": "object",
"required": [
"level",
"value"
],
"properties": {
"level": {
"type": "integer",
"maximum": 99,
"minimum": 1,
"description": "Percentile level, for example 10, 50, or 90."
},
"value": {
"type": "string",
"description": "Decimal-string value at this percentile."
}
}
},
"optionProbability": {
"type": "object",
"required": [
"optionId",
"probability"
],
"properties": {
"optionId": {
"type": "string",
"maxLength": 640,
"minLength": 1,
"description": "Stable id from the subject question's multi.optionIds array.",
"maxGraphemes": 64,
"minGraphemes": 1
},
"probability": {
"type": "integer",
"maximum": 100,
"minimum": 0,
"description": "Percent probability assigned to this option."
}
}
}
},
"$type": "com.atproto.lexicon.schema",
"lexicon": 1
}