{"record":{"id":"89a63801ee6cb39b","repo":"Hmbown/CodeWhale","slug":"kind-is-missing-required-field-dotted","errorCode":null,"errorMessage":"{kind} is missing required field `{dotted}`","messagePattern":"(.+?) is missing required field `(.+?)`","errorType":"exception","errorClass":"RuntimeContractError","httpStatus":null,"severity":"error","filePath":"scripts/check-runtime-contract-budget.py","lineNumber":195,"sourceCode":"            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\ndef validate_identity_structure(document: dict[str, Any], kind: str) -> None:\n    profile = required_value(document, (\"tool_catalog\", \"surface_profile\"), kind)\n    if profile != TOOL_SURFACE_PROFILE:\n        raise RuntimeContractError(\n            f\"{kind} tool surface_profile must be `{TOOL_SURFACE_PROFILE}`, \"\n            f\"got {profile!r}\"\n        )\n\n    for mode, _label in VISIBLE_MODES:\n        for surface, _surface_label in TOOL_SURFACES:","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-runtime-contract-budget.py#L177-L213","documentation":"required_value walked a dotted metric path (for example tool_catalog.modes.plan.full.tools) and hit either a non-dict intermediate value or a missing key. The METRICS/IDENTITIES tables in the checker define every path that must exist in both receipt and budget, so this fires when the JSON lacks a section — typically a budget predating newly added metrics, or a hand-edited document with deleted keys.","triggerScenarios":"The checker gained new metrics (schema growth) but scripts/runtime-contract-budget.json was not regenerated; a hand-edit deleted a nested section; a receipt produced by an older measure-runtime-contract.py.","commonSituations":"Pulling checker updates that add metrics; partial manual budget edits; stale receipts from old branches.","solutions":["Add the missing nested section named by the dotted path to the JSON document","Regenerate the budget from a passing measurement: `python3 scripts/check-runtime-contract-budget.py --update`","Regenerate stale receipts with the current scripts/measure-runtime-contract.py"],"exampleFix":"// before — budget JSON lacks the section tool_catalog.modes.operate.active\n// after — regenerate instead of hand-patching\n# python3 scripts/measure-runtime-contract.py > receipt.json\n# python3 scripts/check-runtime-contract-budget.py --receipt receipt.json --update","handlingStrategy":"validation","validationCode":"def has_path(doc, parts):\n    for p in parts:\n        if not isinstance(doc, dict) or p not in doc:\n            return False\n        doc = doc[p]\n    return True\nassert all(has_path(budget, path) for path, _ in METRICS)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Regenerate budgets with --update after checker updates add metrics","Never delete nested sections from budget JSON","Keep the measure script and checker from the same commit"],"tags":["python","json","schema","validation"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}