{"record":{"id":"c8de3e97ab7b440b","repo":"Hmbown/CodeWhale","slug":"budget-needs-ceilings-and-baseline-observation-obj","errorCode":null,"errorMessage":"budget needs ceilings and baseline_observation objects","messagePattern":"budget needs ceilings and baseline_observation objects","errorType":"exception","errorClass":"PersistenceBacklogError","httpStatus":null,"severity":"error","filePath":"scripts/check-persistence-backlog-budget.py","lineNumber":260,"sourceCode":"def validate_budget(budget: dict[str, Any]) -> None:\n    if budget.get(\"document_kind\") != BUDGET_KIND:\n        raise PersistenceBacklogError(f\"budget document_kind must be {BUDGET_KIND}\")\n    if budget.get(\"schema_version\") != SCHEMA_VERSION:\n        raise PersistenceBacklogError(\"budget schema_version changed\")\n    fixture = budget.get(\"fixture\")\n    if not isinstance(fixture, dict) or set(fixture) != set(FIXTURE):\n        raise PersistenceBacklogError(\"budget fixture no longer matches the frozen workload\")\n    for field, expected in FIXTURE.items():\n        if type(fixture[field]) is not type(expected) or fixture[field] != expected:\n            raise PersistenceBacklogError(\n                f\"budget fixture.{field} must remain {expected!r}\"\n            )\n    if budget.get(\"baseline_receipt\") != BASELINE_RECEIPT_REFERENCE:\n        raise PersistenceBacklogError(\"budget baseline_receipt path changed\")\n    ceilings = budget.get(\"ceilings\")\n    baseline = budget.get(\"baseline_observation\")\n    if not isinstance(ceilings, dict) or not isinstance(baseline, dict):\n        raise PersistenceBacklogError(\"budget needs ceilings and baseline_observation objects\")\n    for field in CEILING_FIELDS:\n        ceiling = non_negative_integer(ceilings.get(field), f\"ceilings.{field}\")\n        observed = non_negative_integer(\n            baseline.get(field), f\"baseline_observation.{field}\"\n        )\n        if observed > ceiling:\n            raise PersistenceBacklogError(\n                f\"baseline_observation.{field} exceeds its ceiling\"\n            )\n    baseline_accepted = non_negative_integer(\n        baseline.get(\"accepted_requests\"), \"baseline_observation.accepted_requests\"\n    )\n    if baseline_accepted != FIXTURE[\"requests_attempted\"]:\n        raise PersistenceBacklogError(\n            \"baseline_observation.accepted_requests must equal requests_attempted\"\n        )\n    baseline_applied = non_negative_integer(\n        baseline.get(\"applied_version\"), \"baseline_observation.applied_version\"","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-persistence-backlog-budget.py#L242-L278","documentation":"Raised by validate_budget() when budget['ceilings'] or budget['baseline_observation'] is missing or not a JSON object. Both blocks are required: ceilings holds the one-way upper bounds for the five CEILING_FIELDS and baseline_observation holds the frozen macOS baseline those ceilings were derived from.","triggerScenarios":"Either key absent, set to null, an array, a scalar, or a typo such as 'ceiling' or 'baseline_observations'.","commonSituations":"Truncating the budget during hand-edits; a merge that dropped one block; generating a budget from a template that omitted baseline_observation.","solutions":["Restore both objects: ceilings with the five ceiling fields, baseline_observation with its observation fields plus provenance","Validate the file with python -m json.tool scripts/persistence-backlog-budget.json before running the checker","Copy the block structure from scripts/persistence-backlog-budget.json at git HEAD"],"exampleFix":"// before (budget.json)\n{ \"document_kind\": \"...\", \"schema_version\": 2, \"fixture\": { ... },\n  \"ceilings\": { ... } }\n\n// after: both objects present\n{ \"document_kind\": \"...\", \"schema_version\": 2, \"fixture\": { ... },\n  \"ceilings\": { ... },\n  \"baseline_observation\": { ..., \"provenance\": { ... } } }","handlingStrategy":"validation","validationCode":"def budget_blocks_ok(budget: dict) -> bool:\n    return (isinstance(budget.get(\"ceilings\"), dict)\n            and isinstance(budget.get(\"baseline_observation\"), dict))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Load budgets from the repo checkout (scripts/persistence-backlog-budget.json) instead of hand-maintained copies","Validate budget JSON with python -m json.tool and a key-set check before running the checker","Change FIXTURE/SCHEMA_VERSION in the checker only together with regenerating budget and baseline receipt in one commit"],"tags":["json","python","ci-gate","configuration"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}