{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://unattended-works.invalid/schema/run.schema.json",
  "title": "Stale Priors Index — test run",
  "description": "One file = one battery run of one model against one library on one date. Findings are reproduced failures, each carrying a primary-source citation. Method integrity rule (CLAUDE.md): an entry ships only with a reproduced failure AND a primary-source citation.",
  "type": "object",
  "required": [
    "run_id",
    "library",
    "model",
    "test",
    "sources",
    "findings"
  ],
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string"
    },
    "run_id": {
      "type": "string",
      "description": "Stable canonical id: <library>--<model_id>--<battery>--<test_date>. Used as the URL slug. The battery segment allows a suffix so replicates of an existing battery (v1r-a, v1r-b) are distinguishable from new batteries (v2, v3).",
      "pattern": "^[a-z0-9.-]+--[a-z0-9.-]+--v[0-9]+[a-z0-9-]*--[0-9]{4}-[0-9]{2}-[0-9]{2}$"
    },
    "supersedes": {
      "type": [
        "string",
        "null"
      ],
      "description": "run_id of an earlier run of the same model x library that this one extends."
    },
    "replicate_of": {
      "type": [
        "string",
        "null"
      ],
      "description": "run_id this run re-measures with the SAME battery prompt, unchanged. A replicate does not supersede what it replicates: both stay published, both keep their URLs, and a disagreement between them is evidence about the instrument rather than a correction to the earlier run."
    },
    "library": {
      "type": "object",
      "required": [
        "name",
        "ecosystem",
        "latest_version_at_test",
        "latest_version_verified_on"
      ],
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string"
        },
        "ecosystem": {
          "type": "string",
          "enum": [
            "npm",
            "pypi",
            "crates",
            "go",
            "maven",
            "rubygems",
            "other"
          ]
        },
        "latest_version_at_test": {
          "type": "string"
        },
        "latest_version_verified_on": {
          "type": [
            "string",
            "null"
          ],
          "format": "date"
        },
        "latest_version_note": {
          "type": "string"
        }
      }
    },
    "model": {
      "type": "object",
      "required": [
        "id",
        "label",
        "vendor",
        "self_reported_cutoff"
      ],
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "vendor": {
          "type": "string"
        },
        "invoked_as": {
          "type": "string",
          "description": "How the subject was spawned, for reproducibility."
        },
        "self_reported_cutoff": {
          "type": [
            "string",
            "null"
          ],
          "description": "YYYY-MM as stated by the model in-session. null = the model did not state one."
        },
        "cutoff_basis": {
          "type": "string",
          "description": "Present when self_reported_cutoff is null or hedged."
        },
        "believed_latest_version": {
          "type": [
            "string",
            "null"
          ]
        },
        "believed_latest_quote": {
          "type": "string"
        },
        "knowledge_stops_at_version": {
          "type": [
            "string",
            "null"
          ],
          "description": "Newest release whose CONTENTS the model could correctly attribute to that release. This measures VERSION ATTRIBUTION, not knowledge of the features: a model past this point often uses a newer API correctly while naming the wrong release for it (JOURNAL/018). Field name kept for continuity with already-published runs."
        },
        "knowledge_stops_on": {
          "type": [
            "string",
            "null"
          ],
          "format": "date",
          "description": "Publication date of knowledge_stops_at_version."
        },
        "knowledge_gap_starts_at_version": {
          "type": [
            "string",
            "null"
          ],
          "description": "Oldest release whose CONTENTS the model could NOT correctly attribute to it — the other end of the boundary interval. Together with knowledge_stops_at_version this brackets the model's ATTRIBUTION boundary for this library (not the point where its knowledge of the library stops; see JOURNAL/018)."
        },
        "knowledge_gap_starts_on": {
          "type": [
            "string",
            "null"
          ],
          "format": "date",
          "description": "Publication date of knowledge_gap_starts_at_version. Must be later than knowledge_stops_on."
        },
        "cutoff_lag_months": {
          "type": [
            "number",
            "null"
          ],
          "description": "Months between knowledge_stops_on and self_reported_cutoff — how far a model's version attribution lags the cutoff it states for itself. The core measurement of this dataset."
        }
      }
    },
    "test": {
      "type": "object",
      "required": [
        "date",
        "battery",
        "tool_uses_during_test",
        "status"
      ],
      "additionalProperties": false,
      "properties": {
        "date": {
          "type": "string",
          "format": "date"
        },
        "battery": {
          "type": "string",
          "description": "e.g. zod/v2"
        },
        "battery_spec": {
          "type": "string",
          "description": "Repo path of the published battery."
        },
        "prompt_file": {
          "type": [
            "string",
            "null"
          ],
          "description": "Repo path under prompts/sent/ of the EXACT text sent to this subject, byte for byte. Two runs were sent an identical prompt if and only if they name the same file; the index groups identical-prompt replicates off this field. null (or absent) means no stored text exists for this run — every battery before 2026-09-01 (JOURNAL/024), whose sent text was only ever reconstructed from prompts/<lib>.md. A null run falls back to the battery-id heuristic and must never be claimed as byte-identical to anything.",
          "pattern": "^prompts/sent/[a-z0-9.-]+\\.txt$"
        },
        "tasks": {
          "type": "integer"
        },
        "direct_questions": {
          "type": "integer"
        },
        "tool_uses_during_test": {
          "type": "integer",
          "description": "Must be 0 for a valid elicitation — the subject answers from training knowledge only."
        },
        "probe_window": {
          "type": [
            "object",
            "null"
          ],
          "description": "Release range the battery probes. Probe fairness rule: only releases published before the subject's stated cutoff are chargeable.",
          "required": [
            "from",
            "to"
          ],
          "additionalProperties": false,
          "properties": {
            "from": {
              "type": "string"
            },
            "to": {
              "type": "string"
            }
          }
        },
        "self_test": {
          "type": "boolean",
          "description": "True when the operator model is the subject. Weaker evidence; disclosed."
        },
        "saturated": {
          "type": "boolean",
          "description": "True when this battery no longer discriminates for this subject."
        },
        "status": {
          "type": "string",
          "enum": [
            "open",
            "retested",
            "superseded"
          ]
        },
        "retested_on": {
          "type": [
            "string",
            "null"
          ],
          "format": "date"
        },
        "elicits_code": {
          "type": "boolean",
          "description": "False for an INSTRUMENT battery: one that asks the subject about its own knowledge (releases, self-placement) rather than for idiomatic library code. Such a run can never produce a reproduced code failure, so it is excluded from the correction pack's 'failures across N runs' denominator, which would otherwise improve as instrument arms are added. Absent means true - every battery before 2026-09-05 elicited code."
        }
      }
    },
    "sources": {
      "type": "array",
      "minItems": 1,
      "description": "Primary sources consulted for verification in this run.",
      "items": {
        "type": "string",
        "format": "uri"
      }
    },
    "findings": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/finding"
      }
    },
    "non_findings": {
      "type": "array",
      "description": "Recorded but not shipped as findings: correct answers, near-misses, imprecisions. Kept because the dataset's value is longitudinal.",
      "items": {
        "$ref": "#/$defs/nonFinding"
      }
    },
    "open_questions": {
      "type": "array",
      "description": "Claims seen but not verified against a primary source. Never ship these as findings.",
      "items": {
        "$ref": "#/$defs/openQuestion"
      }
    },
    "summary": {
      "type": "string",
      "description": "One-paragraph plain-language result."
    },
    "markdown": {
      "type": "string",
      "description": "Repo path of the human-readable write-up this file is derived from."
    }
  },
  "$defs": {
    "citation": {
      "type": "object",
      "required": [
        "url",
        "title"
      ],
      "additionalProperties": false,
      "properties": {
        "url": {
          "type": "string",
          "format": "uri"
        },
        "title": {
          "type": "string"
        },
        "published_on": {
          "type": [
            "string",
            "null"
          ],
          "format": "date"
        },
        "quote": {
          "type": "string",
          "description": "Verbatim from the primary source."
        }
      }
    },
    "finding": {
      "type": "object",
      "required": [
        "id",
        "severity",
        "severity_label",
        "title",
        "chargeable",
        "model_belief",
        "citations"
      ],
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^F[0-9]+$"
        },
        "severity": {
          "type": "string",
          "enum": [
            "S1",
            "S2",
            "S3",
            "S4"
          ]
        },
        "severity_label": {
          "type": "string",
          "enum": [
            "breaks-build",
            "silently-wrong",
            "deprecated",
            "wrong-metadata"
          ]
        },
        "title": {
          "type": "string"
        },
        "api": {
          "type": [
            "string",
            "null"
          ],
          "description": "The API surface the finding is about."
        },
        "change_kind": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "added",
            "removed",
            "renamed",
            "now-throws",
            "behavior-changed",
            "stricter",
            "requirement",
            "deprecated",
            "version-fact",
            null
          ]
        },
        "introduced_in": {
          "type": [
            "string",
            "null"
          ],
          "description": "Library version at which the model's belief became wrong."
        },
        "introduced_on": {
          "type": [
            "string",
            "null"
          ],
          "format": "date"
        },
        "chargeable": {
          "type": "boolean",
          "description": "Probe fairness rule: true only when introduced_on precedes the subject's stated cutoff. A false here is not a pass — it is a scheduled retest."
        },
        "chargeable_note": {
          "type": "string"
        },
        "model_belief": {
          "type": "string",
          "description": "What the model asserted. Quoted verbatim where the write-up quotes it."
        },
        "wrong_code": {
          "type": [
            "string",
            "null"
          ]
        },
        "correct_code": {
          "type": [
            "string",
            "null"
          ]
        },
        "impact": {
          "type": "string",
          "description": "What it costs the user who acts on the belief."
        },
        "citations": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/citation"
          }
        },
        "scope_note": {
          "type": "string",
          "description": "Limits of what was actually verified."
        },
        "withdrawn": {
          "type": "object",
          "description": "A charge the Index has RETRACTED. The finding stays published on its run page, with its original text intact and a retraction notice attached; it is excluded from every count, every aggregate listing, every correction pack and the MCP tools. History is never deleted.",
          "required": [
            "on",
            "reason",
            "journal"
          ],
          "additionalProperties": false,
          "properties": {
            "on": {
              "type": "string",
              "format": "date"
            },
            "reason": {
              "type": "string",
              "description": "Why the charge was wrong. Stated against the subject, not against the finding's author."
            },
            "journal": {
              "type": "string",
              "pattern": "^JOURNAL/[0-9]{3}$"
            }
          }
        }
      }
    },
    "nonFinding": {
      "type": "object",
      "required": [
        "kind",
        "summary"
      ],
      "additionalProperties": false,
      "properties": {
        "kind": {
          "type": "string",
          "enum": [
            "correct",
            "miss",
            "imprecision",
            "context"
          ]
        },
        "summary": {
          "type": "string"
        },
        "api": {
          "type": [
            "string",
            "null"
          ]
        },
        "introduced_in": {
          "type": [
            "string",
            "null"
          ]
        },
        "chargeable_miss": {
          "type": "boolean",
          "description": "A miss inside the fairness window that the write-up counts as chargeable without giving it an F-number."
        },
        "miss_class": {
          "type": "string",
          "enum": [
            "non_charging_arm",
            "stated_cutoff",
            "no_severity_level",
            "probe_class",
            "unreproduced"
          ],
          "description": "Required when chargeable_miss is true. When charged_on is null, this is the binding rule that keeps the failure out of the site's chargeable finding count. When charged_on names a run, the failure IS counted there and this records why this particular draw carries no F-number."
        },
        "charged_on": {
          "type": [
            "string",
            "null"
          ],
          "description": "run_id of the run that charges this same failure against this same subject as a chargeable finding, when one does. Null means the failure is absent from the finding count entirely."
        },
        "why_not_a_finding": {
          "type": "string"
        }
      }
    },
    "openQuestion": {
      "type": "object",
      "required": [
        "question",
        "status"
      ],
      "additionalProperties": false,
      "properties": {
        "question": {
          "type": "string"
        },
        "status": {
          "type": "string",
          "enum": [
            "open",
            "resolved-finding",
            "resolved-non-finding"
          ]
        },
        "resolution": {
          "type": "string"
        },
        "resolved_in_run": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    }
  }
}
