ProblemRevision schema
Generated from the canonical schema
schemas/problem-revision.schema.jsonbyscripts/generate-schema-docs.mjs— do not edit this page by hand.
One immutable, exact specification of a Problem: the statement and context an Attempt actually works against, plus the pinned verification and Skill references in force at that time. Every Attempt records exactly one ProblemRevision, so historical work stays interpretable forever. A semantic change to the task creates a new revision; revisions are never edited or deleted.
Schema version: 1.5.0 · $id: https://tokensforprogress.org/schemas/problem-revision.schema.json
Fields
id
Type: string · Required: yes · Mutable: no · Pattern: ^prv_[0-9a-z]{10,32}$
Stable opaque identifier for this revision. This is the id Attempts pin.
Example: "prv_01jf8zq7h3nd"
problem_id
Type: string · Required: yes · Mutable: no · Pattern: ^prb_[0-9a-z]{10,32}$
The Problem this revision specifies.
Example: "prb_01jf8z4m2xkq"
revision_number
Type: integer · Required: yes · Mutable: no
Sequential position in this Problem's revision history, starting at 1. Unique per problem_id.
Example: 3
statement_md
Type: string · Required: yes · Mutable: no
The exact task statement, in Markdown: what to produce, inputs, expected shape of output, and constraints. This is the text a person or agent works against. Any semantic change to it belongs in a new revision.
Example: "Produce a structured transfer dossier for patent US-XXXXXXX containing..."
context_md
Type: string \| null · Required: yes · Mutable: no
Supporting context in Markdown: background, pointers to sources, prior-work notes, caveats. Null when the statement stands alone. Distinct from statement_md so tooling can present task vs. background separately.
Example: "The patent expires in 2031. Related prior dossiers: ..."
benchmark
Type: object \| null · Required: yes · Mutable: no
Scoring semantics; present if and only if the Problem's structure is BENCHMARK, null otherwise. Deliberately minimal — how the score is computed and trusted is the verification contract's job; this block only defines what the number means and how results compare.
benchmark.metric_name
Type: string · Required: yes · Mutable: no
Human-readable name of the metric being optimized.
Example: "proof length (lines)"
benchmark.direction
Type: maximize | minimize · Required: yes · Mutable: no
Whether higher or lower scores are better. Determines what 'current record' means.
Example: "minimize"
benchmark.unit
Type: string \| null · Required: no · Mutable: no · Default: null
Display unit for scores, when one exists.
Example: "lines"
benchmark.baseline
Type: number \| null · Required: no · Mutable: no · Default: null
Optional reference score (e.g. the state of the art when the revision was published). A Submission does not have to beat it to be valid; it anchors comparison.
Example: 412
verifier_contract_id
Type: string \| null · Required: yes · Mutable: no
Pins the immutable VerifierContract defining what a valid, verified result means for this revision (and, for BENCHMARK, how the score is computed). The Contract's reference_inputs slots are bound by verifier_input_bindings. Null is permitted and is an explicit state, not an omission: results are recorded and not checked.
Example: "vct_01jf90aa4rrc"
verifier_input_bindings
Type: array · Required: yes · Mutable: no · Default: []
Stage 6A extension (approved). Binds each reference_inputs slot declared by the pinned VerifierContract to exact content — the CNF instance a SAT assignment must satisfy, the theorem statement a proof must close. A binding is either stored (no url: content-addressed bytes kept with this revision; at publication the bytes exist and the server-computed hash and size match) or linked (url present, since 1.5.0: the content lives at that public https URL, TfP stores no bytes, and content_hash and size_bytes are as stated by the author, never fetched or checked by TfP; sandbox stages do not mount a linked slot). In both forms: every required slot is bound exactly once, no unknown slots, and media type and size satisfy the slot's constraints. Immutable with the revision. Empty when the revision pins no Contract or the Contract declares no slots.
Example: []
verifier_input_bindings[].key
Type: string · Required: yes · Mutable: — · Pattern: ^[a-z0-9]+(_[a-z0-9]+)*$
The Contract slot bound.
Example: "instance"
verifier_input_bindings[].content_hash
Type: string · Required: yes · Mutable: — · Pattern: ^sha256:[0-9a-f]{64}$
Hash of the bound content. Stored binding: computed by the server from the stored bytes. Linked binding (url present): stated by the author; TfP does not fetch the URL to check it. Readers of a linked input compare what they fetch against this value themselves.
Example: "sha256:3f786850e387550fdab836ed7e6dc881de23001b3f786850e387550fdab836ed"
verifier_input_bindings[].size_bytes
Type: integer · Required: yes · Mutable: —
Size of the bound content in bytes. Stored binding: computed by the server. Linked binding: stated by the author. Must not exceed the slot's max_bytes in either form.
Example: 4821
verifier_input_bindings[].media_type
Type: string · Required: yes · Mutable: —
Canonicalized media type of the bound content; must be one the slot's media_types allows (when that list is non-empty) in both forms.
Example: "text/plain"
verifier_input_bindings[].filename
Type: string · Required: no · Mutable: —
The file's original name (basename) as published; the name the bytes are mounted under in the sandbox (/input/reference/
Example: "air05.mps.gz"
verifier_input_bindings[].url
Type: string · Required: no · Mutable: — · Pattern: ^https://[^\s]+$
Since 1.5.0. Present on a linked binding only: the public https URL where the slot's content lives. TfP stores no bytes for the slot, serves GET /api/problem-revisions/{id}/reference/{key} as a redirect to this URL, lists the URL wherever the revision's reference inputs are listed, and never mounts the slot for a sandbox stage. content_hash and size_bytes are the author's statement about the content at this URL.
Example: "https://journals.example.org/archive/1974/paper-0512.pdf"
sealing
Type: object \| null · Required: no · Mutable: no · Default: null
Immutable sealed evaluation policy; derived evaluation_id, unsealed_at and release_event are supplied by TfP. Independent entries require a submission cutoff.
Example: null
sealing.sealed_until
Type: string · Required: yes · Mutable: —
RFC 3339 UTC timestamp: the latest moment the sealed inputs stay sealed. In the future at publication. The Problem's managers may end sealing earlier; nobody can postpone it.
Example: "2027-06-01T00:00:00Z"
sealing.submission_limit
Type: object · Required: yes · Mutable: —
While sealed, each User may create at most max_submissions Submissions across all revisions of the same evaluation in a rolling window_hours, including withdrawn or invalid Submissions. Statement edits do not reset the budget. Local preflight and operator reruns consume no quota.
sealing.unsealed_at
Type: string \| null · Required: yes · Mutable: —
Derived by TfP, never authored. Null while the inputs are sealed; afterwards the moment sealing ended: sealed_until, or earlier if the Problem was unsealed early.
Example: null
sealing.submission_closes_at
Type: string \| null · Required: no · Mutable: — · Default: null
Optional immutable admission cutoff, including existing Attempts; future at publication and no later than sealed_until. It remains in force after unsealing.
sealing.score_release
Type: object · Required: yes · Mutable: —
immediate requires null release_at. final_only withholds protected evaluation results and the final score until release_at: a future time at publication, no earlier than submission_closes_at when present and no later than sealed_until. Early label release also releases scores. Operational status and public validation feedback remain visible.
sealing.release_event
Type: object \| null · Required: yes · Mutable: — · Default: null
Public append-only early-release audit event. Null before an explicit early unseal, including a release reached only by the scheduled date. Shared-hash cascades retain the initiating manager and reason.
sealing.entries
Type: collaborative | independent · Required: no · Mutable: — · Default: "collaborative"
Independent entries are private until submission_closes_at and require a nominated final submission. Collaborative entries retain normal Problem visibility.
sealing.evaluation_id
Type: string \| null · Required: no · Mutable: — · Pattern: ^sev_[0-9a-f]{32}$
Derived stable evaluation identity. Exact aliases share protected hashes, release authority, policy and submission budget. Never authored.
skill_refs
Type: array · Required: yes · Mutable: no · Default: []
Pinned SkillVersions an attempter should load, each marked required or recommended. Empty when no Skills apply. References are always exact immutable versions, never floating Skills.
skill_refs[].skill_version_id
Type: string · Required: yes · Mutable: no · Pattern: ^skv_[0-9a-z]{10,32}$
The immutable SkillVersion being referenced.
Example: "skv_01jf90m8e2pz"
skill_refs[].requirement
Type: required | recommended · Required: yes · Mutable: no
Whether an Attempt is expected to load this Skill (required) or merely advised to (recommended).
Example: "required"
changelog_md
Type: string \| null · Required: yes · Mutable: no
What changed relative to the previous revision and why, in Markdown. Null for revision_number 1.
Example: "Tightened the output format; the previous wording allowed ambiguous units."
created_by_user_id
Type: string · Required: yes · Mutable: no · Pattern: ^usr_[0-9a-z]{10,32}$
The User who authored and published this revision. The User object itself is specified at Stage 2.
Example: "usr_01jf8xw3tempo"
created_at
Type: string · Required: yes · Mutable: no
RFC 3339 UTC timestamp of publication. Revisions have no updated_at: they are never updated.
Example: "2026-08-30T17:15:02Z"
JSON Schema source
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://tokensforprogress.org/schemas/problem-revision.schema.json",
"title": "ProblemRevision",
"description": "One immutable, exact specification of a Problem: the statement and context an Attempt actually works against, plus the pinned verification and Skill references in force at that time. Every Attempt records exactly one ProblemRevision, so historical work stays interpretable forever. A semantic change to the task creates a new revision; revisions are never edited or deleted.",
"x-tfp-version": "1.5.0",
"type": "object",
"additionalProperties": false,
"required": [
"id",
"problem_id",
"revision_number",
"statement_md",
"context_md",
"benchmark",
"verifier_contract_id",
"verifier_input_bindings",
"skill_refs",
"changelog_md",
"created_by_user_id",
"created_at"
],
"properties": {
"id": {
"type": "string",
"pattern": "^prv_[0-9a-z]{10,32}$",
"x-mutable": false,
"description": "Stable opaque identifier for this revision. This is the id Attempts pin.",
"examples": [
"prv_01jf8zq7h3nd"
]
},
"problem_id": {
"type": "string",
"pattern": "^prb_[0-9a-z]{10,32}$",
"x-mutable": false,
"description": "The Problem this revision specifies.",
"examples": [
"prb_01jf8z4m2xkq"
]
},
"revision_number": {
"type": "integer",
"minimum": 1,
"x-mutable": false,
"description": "Sequential position in this Problem's revision history, starting at 1. Unique per problem_id.",
"examples": [
3
]
},
"statement_md": {
"type": "string",
"minLength": 1,
"x-mutable": false,
"description": "The exact task statement, in Markdown: what to produce, inputs, expected shape of output, and constraints. This is the text a person or agent works against. Any semantic change to it belongs in a new revision.",
"examples": [
"Produce a structured transfer dossier for patent US-XXXXXXX containing..."
]
},
"context_md": {
"type": [
"string",
"null"
],
"x-mutable": false,
"description": "Supporting context in Markdown: background, pointers to sources, prior-work notes, caveats. Null when the statement stands alone. Distinct from statement_md so tooling can present task vs. background separately.",
"examples": [
"The patent expires in 2031. Related prior dossiers: ..."
]
},
"benchmark": {
"type": [
"object",
"null"
],
"x-mutable": false,
"description": "Scoring semantics; present if and only if the Problem's structure is BENCHMARK, null otherwise. Deliberately minimal — how the score is computed and trusted is the verification contract's job; this block only defines what the number means and how results compare.",
"additionalProperties": false,
"required": [
"metric_name",
"direction"
],
"properties": {
"metric_name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"x-mutable": false,
"description": "Human-readable name of the metric being optimized.",
"examples": [
"proof length (lines)"
]
},
"direction": {
"type": "string",
"enum": [
"maximize",
"minimize"
],
"x-mutable": false,
"description": "Whether higher or lower scores are better. Determines what 'current record' means.",
"examples": [
"minimize"
]
},
"unit": {
"type": [
"string",
"null"
],
"default": null,
"x-mutable": false,
"description": "Display unit for scores, when one exists.",
"examples": [
"lines",
"%",
null
]
},
"baseline": {
"type": [
"number",
"null"
],
"default": null,
"x-mutable": false,
"description": "Optional reference score (e.g. the state of the art when the revision was published). A Submission does not have to beat it to be valid; it anchors comparison.",
"examples": [
412
]
}
}
},
"verifier_contract_id": {
"type": [
"string",
"null"
],
"x-mutable": false,
"description": "Pins the immutable VerifierContract defining what a valid, verified result means for this revision (and, for BENCHMARK, how the score is computed). The Contract's reference_inputs slots are bound by verifier_input_bindings. Null is permitted and is an explicit state, not an omission: results are recorded and not checked.",
"examples": [
"vct_01jf90aa4rrc",
null
]
},
"verifier_input_bindings": {
"type": "array",
"maxItems": 10,
"default": [],
"x-mutable": false,
"uniqueItems": true,
"description": "Stage 6A extension (approved). Binds each reference_inputs slot declared by the pinned VerifierContract to exact content — the CNF instance a SAT assignment must satisfy, the theorem statement a proof must close. A binding is either stored (no `url`: content-addressed bytes kept with this revision; at publication the bytes exist and the server-computed hash and size match) or linked (`url` present, since 1.5.0: the content lives at that public https URL, TfP stores no bytes, and `content_hash` and `size_bytes` are as stated by the author, never fetched or checked by TfP; sandbox stages do not mount a linked slot). In both forms: every required slot is bound exactly once, no unknown slots, and media type and size satisfy the slot's constraints. Immutable with the revision. Empty when the revision pins no Contract or the Contract declares no slots.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"key",
"content_hash",
"size_bytes",
"media_type"
],
"properties": {
"key": {
"type": "string",
"pattern": "^[a-z0-9]+(_[a-z0-9]+)*$",
"maxLength": 40,
"description": "The Contract slot bound.",
"examples": [
"instance"
]
},
"content_hash": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$",
"description": "Hash of the bound content. Stored binding: computed by the server from the stored bytes. Linked binding (`url` present): stated by the author; TfP does not fetch the URL to check it. Readers of a linked input compare what they fetch against this value themselves.",
"examples": [
"sha256:3f786850e387550fdab836ed7e6dc881de23001b3f786850e387550fdab836ed"
]
},
"size_bytes": {
"type": "integer",
"minimum": 0,
"description": "Size of the bound content in bytes. Stored binding: computed by the server. Linked binding: stated by the author. Must not exceed the slot's max_bytes in either form.",
"examples": [
4821
]
},
"media_type": {
"type": "string",
"minLength": 1,
"maxLength": 120,
"description": "Canonicalized media type of the bound content; must be one the slot's media_types allows (when that list is non-empty) in both forms.",
"examples": [
"text/plain"
]
},
"filename": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "The file's original name (basename) as published; the name the bytes are mounted under in the sandbox (/input/reference/<key>/<filename>). Absent on revisions published before filenames were recorded, whose mount name is derived from media_type. Optional on a linked binding, where it only labels the link.",
"examples": [
"air05.mps.gz"
]
},
"url": {
"type": "string",
"pattern": "^https://[^\\s]+$",
"maxLength": 2048,
"description": "Since 1.5.0. Present on a linked binding only: the public https URL where the slot's content lives. TfP stores no bytes for the slot, serves GET /api/problem-revisions/{id}/reference/{key} as a redirect to this URL, lists the URL wherever the revision's reference inputs are listed, and never mounts the slot for a sandbox stage. content_hash and size_bytes are the author's statement about the content at this URL.",
"examples": [
"https://journals.example.org/archive/1974/paper-0512.pdf"
]
}
}
},
"examples": [
[]
]
},
"sealing": {
"type": [
"object",
"null"
],
"default": null,
"x-mutable": false,
"description": "Immutable sealed evaluation policy; derived evaluation_id, unsealed_at and release_event are supplied by TfP. Independent entries require a submission cutoff.",
"additionalProperties": false,
"required": [
"sealed_until",
"score_release",
"submission_limit",
"unsealed_at",
"release_event"
],
"properties": {
"sealed_until": {
"type": "string",
"format": "date-time",
"description": "RFC 3339 UTC timestamp: the latest moment the sealed inputs stay sealed. In the future at publication. The Problem's managers may end sealing earlier; nobody can postpone it.",
"examples": [
"2027-06-01T00:00:00Z"
]
},
"submission_limit": {
"type": "object",
"additionalProperties": false,
"required": [
"max_submissions",
"window_hours"
],
"description": "While sealed, each User may create at most max_submissions Submissions across all revisions of the same evaluation in a rolling window_hours, including withdrawn or invalid Submissions. Statement edits do not reset the budget. Local preflight and operator reruns consume no quota.",
"properties": {
"max_submissions": {
"type": "integer",
"minimum": 1,
"maximum": 1000,
"description": "Submissions allowed per User per window.",
"examples": [
5
]
},
"window_hours": {
"type": "integer",
"minimum": 1,
"maximum": 8760,
"description": "Length of the rolling window, in hours.",
"examples": [
24
]
}
}
},
"unsealed_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "Derived by TfP, never authored. Null while the inputs are sealed; afterwards the moment sealing ended: sealed_until, or earlier if the Problem was unsealed early.",
"examples": [
null,
"2027-06-01T00:00:00Z"
]
},
"submission_closes_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"default": null,
"description": "Optional immutable admission cutoff, including existing Attempts; future at publication and no later than sealed_until. It remains in force after unsealing."
},
"score_release": {
"type": "object",
"additionalProperties": false,
"required": [
"mode",
"release_at"
],
"properties": {
"mode": {
"type": "string",
"enum": [
"immediate",
"final_only"
]
},
"release_at": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"description": "immediate requires null release_at. final_only withholds protected evaluation results and the final score until release_at: a future time at publication, no earlier than submission_closes_at when present and no later than sealed_until. Early label release also releases scores. Operational status and public validation feedback remain visible."
},
"release_event": {
"type": [
"object",
"null"
],
"default": null,
"additionalProperties": false,
"x-derived": true,
"description": "Public append-only early-release audit event. Null before an explicit early unseal, including a release reached only by the scheduled date. Shared-hash cascades retain the initiating manager and reason.",
"required": [
"unsealed_at",
"user_id",
"reason_md"
],
"properties": {
"unsealed_at": {
"type": "string",
"format": "date-time",
"description": "Timestamp of the explicit irreversible release."
},
"user_id": {
"type": "string",
"pattern": "^usr_[0-9a-z]{10,32}$",
"description": "The manager who initiated release."
},
"reason_md": {
"type": "string",
"minLength": 1,
"maxLength": 4000,
"description": "The manager’s public reason for early release."
}
}
},
"entries": {
"type": "string",
"enum": [
"collaborative",
"independent"
],
"default": "collaborative",
"description": "Independent entries are private until submission_closes_at and require a nominated final submission. Collaborative entries retain normal Problem visibility."
},
"evaluation_id": {
"type": [
"string",
"null"
],
"pattern": "^sev_[0-9a-f]{32}$",
"description": "Derived stable evaluation identity. Exact aliases share protected hashes, release authority, policy and submission budget. Never authored."
}
},
"examples": [
null
],
"allOf": [
{
"if": {
"type": "object",
"required": [
"entries"
],
"properties": {
"entries": {
"const": "independent"
}
}
},
"then": {
"required": [
"submission_closes_at"
],
"properties": {
"submission_closes_at": {
"type": "string",
"format": "date-time"
}
}
}
}
]
},
"skill_refs": {
"type": "array",
"default": [],
"x-mutable": false,
"description": "Pinned SkillVersions an attempter should load, each marked required or recommended. Empty when no Skills apply. References are always exact immutable versions, never floating Skills.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"skill_version_id",
"requirement"
],
"properties": {
"skill_version_id": {
"type": "string",
"x-mutable": false,
"description": "The immutable SkillVersion being referenced.",
"examples": [
"skv_01jf90m8e2pz"
],
"pattern": "^skv_[0-9a-z]{10,32}$"
},
"requirement": {
"type": "string",
"enum": [
"required",
"recommended"
],
"x-mutable": false,
"description": "Whether an Attempt is expected to load this Skill (required) or merely advised to (recommended).",
"examples": [
"required"
]
}
}
}
},
"changelog_md": {
"type": [
"string",
"null"
],
"x-mutable": false,
"description": "What changed relative to the previous revision and why, in Markdown. Null for revision_number 1.",
"examples": [
"Tightened the output format; the previous wording allowed ambiguous units."
]
},
"created_by_user_id": {
"type": "string",
"pattern": "^usr_[0-9a-z]{10,32}$",
"x-mutable": false,
"description": "The User who authored and published this revision. The User object itself is specified at Stage 2.",
"examples": [
"usr_01jf8xw3tempo"
]
},
"created_at": {
"type": "string",
"format": "date-time",
"x-mutable": false,
"description": "RFC 3339 UTC timestamp of publication. Revisions have no updated_at: they are never updated.",
"examples": [
"2026-08-30T17:15:02Z"
]
}
}
}