{"record":{"id":"8ac95eb70e134b6e","repo":"Hmbown/CodeWhale","slug":"kind-metric-dotted-must-be-a-non-negative-in","errorCode":null,"errorMessage":"{kind} metric `{dotted}` must be a non-negative integer","messagePattern":"(.+?) metric `(.+?)` must be a non-negative integer","errorType":"exception","errorClass":"RuntimeContractError","httpStatus":null,"severity":"error","filePath":"scripts/check-runtime-contract-budget.py","lineNumber":299,"sourceCode":"    representative = budget.get(\"representative_context\")\n    fixture_id = (\n        representative.get(\"fixture_id\")\n        if isinstance(representative, dict)\n        else None\n    )\n    if fixture_id != REPRESENTATIVE_FIXTURE_ID:\n        raise RuntimeContractError(\n            \"budget metric `representative_context.fixture_id` must be \"\n            f\"`{REPRESENTATIVE_FIXTURE_ID}`, got {fixture_id!r}\"\n        )\n    validate_identity_structure(budget, \"budget\")\n\n\ndef metric_value(document: dict[str, Any], path: MetricPath, kind: str) -> int:\n    value = required_value(document, path, kind)\n    dotted = \".\".join(path)\n    if isinstance(value, bool) or not isinstance(value, int) or value < 0:\n        raise RuntimeContractError(\n            f\"{kind} metric `{dotted}` must be a non-negative integer\"\n        )\n    return value\n\n\ndef compare(\n    receipt: dict[str, Any], budget: dict[str, Any]\n) -> tuple[list[MetricResult], list[MetricResult]]:\n    \"\"\"Return (increases, decreases) as path/label/current/ceiling tuples.\"\"\"\n    validate_receipt(receipt)\n    validate_budget(budget)\n    for path, label in IDENTITIES:\n        receipt_value = required_value(receipt, path, \"receipt\")\n        budget_value = required_value(budget, path, \"budget\")\n        if receipt_value != budget_value:\n            detail = \"\"\n            if isinstance(receipt_value, list) and isinstance(budget_value, list):\n                added = [str(item) for item in receipt_value if item not in budget_value]","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-runtime-contract-budget.py#L281-L317","documentation":"metric_value() enforces that every METRICS path (system-prompt bytes/tokens/blocks per mode, stage bytes and deltas, tool counts and schema bytes/tokens, skill-discovery deltas) is a non-negative integer, with bool explicitly rejected because bool is a subclass of int in Python. It runs inside compare() for both receipt and budget documents, and inside budget_from_receipt(). The message names the exact dotted path.","triggerScenarios":"A metric stored as a float (2149.0), a numeric string (\"6084\"), a negative number, or true/false - typically after hand-editing the budget JSON. Also a measure-script change that starts emitting float token estimates.","commonSituations":"Hand-tightening a ceiling in the budget and typing a decimal or string; JSON round-trips through tooling that coerces ints to floats (some YAML/JS pipelines); a receipt edited in a JSON editor that quotes numbers.","solutions":["Rewrite the named metric as a plain non-negative JSON integer (no quotes, no decimal point, no sign)","Sweep the whole file for the same defect: python3 -c \"import json;d=json.load(open('scripts/runtime-contract-budget.json'));print([k for k,v in walk(d) if isinstance(v,float)])\" style scan","If the measure script is emitting floats, fix its serialization to int before re-measuring"],"exampleFix":"// before\n\"total_tokens_est\": 2149.0\n\"system_prompt_bytes\": \"6084\"\n\n// after\n\"total_tokens_est\": 2149\n\"system_prompt_bytes\": 6084","handlingStrategy":"type-guard","validationCode":"def all_metrics_are_ints(doc: dict) -> bool:\n    stack = [doc]\n    while stack:\n        node = stack.pop()\n        if isinstance(node, dict):\n            stack.extend(node.values())\n        elif isinstance(node, list):\n            stack.extend(node)\n        elif isinstance(node, float) or isinstance(node, bool):\n            return False\n    return True","typeGuard":"def is_non_negative_int(value: object) -> bool:\n    return isinstance(value, int) and not isinstance(value, bool) and value >= 0","tryCatchPattern":null,"preventionTips":["Never store metrics as strings or floats in the budget JSON, even transiently","Migrate metrics with a script that coerces via int(round(x)) rather than by hand","Remember bool is an int subclass in Python - the checker deliberately rejects true/false metrics"],"tags":["python","json","typing","validation","budget"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}