{"record":{"id":"4f6d251104112914","repo":"Hmbown/CodeWhale","slug":"source-document-kind-must-be-expected-kind","errorCode":null,"errorMessage":"{source} document_kind must be `{expected_kind}`, got {actual_kind!r}","messagePattern":"(.+?) document_kind must be `(.+?)`, got (.+?)","errorType":"exception","errorClass":"RuntimeContractError","httpStatus":null,"severity":"error","filePath":"scripts/check-runtime-contract-budget.py","lineNumber":176,"sourceCode":"\ndef load_json(path: Path, kind: str) -> dict[str, Any]:\n    try:\n        document = json.loads(path.read_text(encoding=\"utf-8\"))\n    except FileNotFoundError as error:\n        raise RuntimeContractError(f\"missing {kind}: {path}\") from error\n    except (OSError, json.JSONDecodeError) as error:\n        raise RuntimeContractError(f\"invalid {kind} {path}: {error}\") from error\n    if not isinstance(document, dict):\n        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:","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-runtime-contract-budget.py#L158-L194","documentation":"validate_document compared the document_kind discriminator and it does not match the expected receipt or budget kind string (`codewhale.runtime_contract_receipt` vs `codewhale.runtime_contract_budget`). The discriminator prevents passing the wrong file into the wrong slot and rejects receipts produced by other gates (for example the persistence-backlog script). A missing document_kind surfaces as None in the message.","triggerScenarios":"Passing the budget file to --receipt; passing a persistence-backlog receipt; hand-building a receipt without the document_kind key; swapping the --receipt and --budget arguments.","commonSituations":"Copy-pasted CI commands; repositories hosting several receipt formats side by side.","solutions":["Confirm which file went where: --receipt wants document_kind `codewhale.runtime_contract_receipt`, the budget wants `codewhale.runtime_contract_budget`","Regenerate receipts with scripts/measure-runtime-contract.py so the discriminator is written for you","Add the correct document_kind key when hand-building test fixtures"],"exampleFix":"# before\npython3 scripts/check-runtime-contract-budget.py --receipt scripts/runtime-contract-budget.json\n# after\npython3 scripts/check-runtime-contract-budget.py --receipt scripts/runtime-contract-receipt.json","handlingStrategy":"validation","validationCode":"expected = 'codewhale.runtime_contract_receipt' if is_receipt else 'codewhale.runtime_contract_budget'\nassert doc.get('document_kind') == expected, doc.get('document_kind')","typeGuard":"def is_receipt(doc):\n    return isinstance(doc, dict) and doc.get('document_kind') == 'codewhale.runtime_contract_receipt'","tryCatchPattern":null,"preventionTips":["Double-check which slot (--receipt vs --budget) each file goes into","Use the measure script to produce receipts so the discriminator is set","Include document_kind in hand-built fixtures"],"tags":["python","json","validation","schema"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}