{"record":{"id":"a96336d8d50266be","repo":"Hmbown/CodeWhale","slug":"source-schema-version-must-be-schema-version","errorCode":null,"errorMessage":"{source} schema_version must be {SCHEMA_VERSION}, got {version!r}","messagePattern":"(.+?) schema_version must be (.+?), got (.+?)","errorType":"exception","errorClass":"RuntimeContractError","httpStatus":null,"severity":"error","filePath":"scripts/check-runtime-contract-budget.py","lineNumber":185,"sourceCode":"        raise RuntimeContractError(f\"invalid {kind} {path}: top level must be an object\")\n    return document\n\n\ndef validate_document(\n    document: dict[str, Any], expected_kind: str, source: str\n) -> None:\n    actual_kind = document.get(\"document_kind\")\n    if actual_kind != expected_kind:\n        raise RuntimeContractError(\n            f\"{source} document_kind must be `{expected_kind}`, got {actual_kind!r}\"\n        )\n    version = document.get(\"schema_version\")\n    if (\n        isinstance(version, bool)\n        or not isinstance(version, int)\n        or version != SCHEMA_VERSION\n    ):\n        raise RuntimeContractError(\n            f\"{source} schema_version must be {SCHEMA_VERSION}, got {version!r}\"\n        )\n\n\ndef required_value(document: dict[str, Any], path: MetricPath, kind: str) -> Any:\n    value: Any = document\n    dotted = \".\".join(path)\n    for part in path:\n        if not isinstance(value, dict) or part not in value:\n            raise RuntimeContractError(f\"{kind} is missing required field `{dotted}`\")\n        value = value[part]\n    return value\n\n\ndef tool_identity_digest(names: list[str]) -> str:\n    return hashlib.sha256(\"\\0\".join(names).encode(\"utf-8\")).hexdigest()\n\n","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-runtime-contract-budget.py#L167-L203","documentation":"The schema_version field is missing, boolean, non-integer, or not exactly SCHEMA_VERSION (currently 1). The explicit bool exclusion exists because Python bools are ints. Receipts and budgets must be produced by the same schema generation as the checker, so version skew in either direction fails fast.","triggerScenarios":"Hand-written receipts with \"schema_version\": \"1\" (string) or 1.0 (float); a checker upgrade that bumped SCHEMA_VERSION while old receipts or budgets are still in use; mixing in receipts from the persistence script, which uses schema_version 2.","commonSituations":"Version skew after pulling new checker code; hand-crafted fixtures; JSON encoders that emit floats for whole numbers.","solutions":["Set \"schema_version\": 1 as a JSON integer in both the receipt and the budget","After upgrading the checker, regenerate receipts and budgets with the matching script version instead of hand-editing","Avoid 1.0, \"1\", and true — the strict type check rejects all of them"],"exampleFix":"// before\n{ \"document_kind\": \"codewhale.runtime_contract_receipt\", \"schema_version\": \"1\" }\n// after\n{ \"document_kind\": \"codewhale.runtime_contract_receipt\", \"schema_version\": 1 }","handlingStrategy":"validation","validationCode":"v = doc.get('schema_version')\nassert isinstance(v, int) and not isinstance(v, bool) and v == 1, repr(v)","typeGuard":"def has_valid_schema_version(doc):\n    v = doc.get('schema_version')\n    return isinstance(v, int) and not isinstance(v, bool) and v == 1","tryCatchPattern":null,"preventionTips":["Regenerate artifacts after checker upgrades","Write schema_version as a plain JSON integer","Do not mix receipts across gates with different schema versions"],"tags":["python","json","schema","versioning"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}