{"record":{"id":"1d89c4e36083a136","repo":"Hmbown/CodeWhale","slug":"field-must-be-a-non-negative-integer","errorCode":null,"errorMessage":"{field} must be a non-negative integer","messagePattern":"(.+?) must be a non-negative integer","errorType":"exception","errorClass":"PersistenceBacklogError","httpStatus":null,"severity":"error","filePath":"scripts/check-persistence-backlog-budget.py","lineNumber":98,"sourceCode":"\n\nclass PersistenceBacklogError(ValueError):\n    \"\"\"A receipt or budget broke the measurement contract.\"\"\"\n\n\ndef load_json(path: Path, label: str) -> dict[str, Any]:\n    try:\n        value = json.loads(path.read_text(encoding=\"utf-8\"))\n    except (OSError, json.JSONDecodeError) as error:\n        raise PersistenceBacklogError(f\"invalid {label} {path}: {error}\") from error\n    if not isinstance(value, dict):\n        raise PersistenceBacklogError(f\"{label} must be a JSON object\")\n    return value\n\n\ndef non_negative_integer(value: Any, field: str) -> int:\n    if isinstance(value, bool) or not isinstance(value, int) or value < 0:\n        raise PersistenceBacklogError(f\"{field} must be a non-negative integer\")\n    return value\n\n\ndef validate_frozen_field(field: str, value: Any, expected: Any) -> None:\n    if type(value) is not type(expected) or value != expected:\n        raise PersistenceBacklogError(\n            f\"receipt {field} must remain {expected!r}, got {value!r}\"\n        )\n\n\ndef current_source_identity() -> dict[str, Any]:\n    def run(command: list[str]) -> str:\n        result = subprocess.run(\n            command,\n            cwd=ROOT,\n            text=True,\n            capture_output=True,\n            check=False,","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-persistence-backlog-budget.py#L80-L116","documentation":"non_negative_integer is the checker's field validator for counts in the budget and receipt documents. It rejects a value that is a bool (bools are ints in Python but explicitly disallowed), not an int (floats and strings fail), or negative. The message interpolates the offending field name so you know exactly which key broke the contract.","triggerScenarios":"A budget field like \"max_files\": -1 or 5000.0; a receipt count serialized as a string (\"3\") by another language's JSON writer; a boolean true/false left in place of a numeric flag. All raise before any comparison against the baseline runs.","commonSituations":"Hand-editing the budget and using a float or negative sentinel; receipts generated by measurement tooling in JS/Go that emits strings or floats for counts; JSON serializers that write 0.0 or 1e3; someone using true as shorthand for 1.","solutions":["Find the named field in the budget/receipt JSON and set it to a whole number >= 0.","If the value comes from a generator script, coerce with int(round(x)) at write time and assert non-negative before serializing.","Remove booleans — numeric contract fields take 0/1, not true/false.","Re-run the checker; field-level errors are reported one at a time, so iterate until the document validates."],"exampleFix":"# before\n{\"max_files\": 5000.0, \"max_retries\": -1}\n# after\n{\"max_files\": 5000, \"max_retries\": 0}","handlingStrategy":"validation","validationCode":"def is_non_negative_integer(value: object) -> bool:\n    return isinstance(value, int) and not isinstance(value, bool) and value >= 0","typeGuard":"def is_count_field(value: object) -> bool:\n    # accepts only true ints in [0, 2**63-1]; rejects bools, floats, strings\n    return (\n        isinstance(value, int)\n        and not isinstance(value, bool)\n        and 0 <= value <= 2**63 - 1\n    )","tryCatchPattern":null,"preventionTips":["Write whole numbers without decimal points in budget/receipt JSON (5000, not 5000.0).","Coerce counts with int() and assert non-negativity in generator scripts before serializing.","Never use true/false where the contract expects 0/1."],"tags":["json","validation","numbers","persistence-budget","ci"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}