{"record":{"id":"e8ac6c5a5fdebbd3","repo":"Hmbown/CodeWhale","slug":"receipt-source-dirty-must-be-boolean","errorCode":null,"errorMessage":"receipt source_dirty must be boolean","messagePattern":"receipt source_dirty must be boolean","errorType":"exception","errorClass":"PersistenceBacklogError","httpStatus":null,"severity":"error","filePath":"scripts/check-persistence-backlog-budget.py","lineNumber":158,"sourceCode":"    require_clean_source: bool = False,\n) -> None:\n    missing = [field for field in REQUIRED_RECEIPT_FIELDS if field not in receipt]\n    if missing:\n        raise PersistenceBacklogError(\n            \"receipt missing required field(s): \" + \", \".join(missing)\n        )\n    if receipt[\"document_kind\"] != RECEIPT_KIND:\n        raise PersistenceBacklogError(f\"receipt document_kind must be {RECEIPT_KIND}\")\n    if receipt[\"schema_version\"] != SCHEMA_VERSION:\n        raise PersistenceBacklogError(\"receipt schema_version changed\")\n    for field, expected in FIXTURE.items():\n        validate_frozen_field(field, receipt[field], expected)\n    if not isinstance(receipt[\"source_sha\"], str) or not SOURCE_SHA_PATTERN.fullmatch(\n        receipt[\"source_sha\"]\n    ):\n        raise PersistenceBacklogError(\"receipt source_sha must be an exact lowercase Git SHA\")\n    if type(receipt[\"source_dirty\"]) is not bool:\n        raise PersistenceBacklogError(\"receipt source_dirty must be boolean\")\n    for field, prefix in ((\"rustc_version\", \"rustc \"), (\"cargo_version\", \"cargo \")):\n        if not isinstance(receipt[field], str) or not receipt[field].startswith(prefix):\n            raise PersistenceBacklogError(f\"receipt {field} must be a version string\")\n    validate_frozen_field(\"build_profile\", receipt[\"build_profile\"], \"test\")\n    validate_frozen_field(\"sample_count\", receipt[\"sample_count\"], 1)\n    if expected_source is not None:\n        for field in (\n            \"source_sha\",\n            \"source_dirty\",\n            \"rustc_version\",\n            \"cargo_version\",\n            \"build_profile\",\n            \"sample_count\",\n        ):\n            if receipt[field] != expected_source[field]:\n                raise PersistenceBacklogError(\n                    f\"receipt {field} does not match the checked source\"\n                )","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-persistence-backlog-budget.py#L140-L176","documentation":"Raised in validate_receipt (scripts/check-persistence-backlog-budget.py:157-158) when type(receipt[\"source_dirty\"]) is not bool. The flag records whether the source tree was dirty at measurement time and is later compared with a live `git status`, so a JSON true/false boolean is mandatory — the check uses exact type() to reject Python/JSON look-alikes.","triggerScenarios":"The emitter storing the string \"true\"/\"false\" instead of a boolean (the measure script passes the env var CODEWHALE_TEST_PERSISTENCE_BACKLOG_SOURCE_DIRTY as lowercase text and the Rust test must parse it back to a bool); null; 0/1 integers.","commonSituations":"Env-var provenance plumbing where the string reaches the JSON unconverted; hand-edited receipts; serializers that coerce booleans to strings.","solutions":["Fix the Rust receipt writer to emit a real JSON boolean (parse the env string with ==\"true\").","Regenerate the receipt after the fix.","Never hand-edit source_dirty to work around a dirty-tree failure — clean the tree instead."],"exampleFix":"// receipt (before)\n\"source_dirty\": \"false\"\n// receipt (after)\n\"source_dirty\": false","handlingStrategy":"type-guard","validationCode":"if type(receipt.get(\"source_dirty\")) is not bool:\n    sys.exit(\"source_dirty must be a JSON boolean; fix the emitter's env parsing\")","typeGuard":"def is_strict_bool(value) -> bool:\n    return type(value) is bool","tryCatchPattern":"try:\n    validate_receipt(receipt)\nexcept PersistenceBacklogError as e:\n    if \"source_dirty must be boolean\" in str(e):\n        raise RuntimeError(\"emitter leaked a string boolean; parse env with == 'true'\") from e\n    raise","preventionTips":["Parse CODEWHALE_TEST_PERSISTENCE_BACKLOG_SOURCE_DIRTY with == \"true\" into a bool in the Rust test.","Serialize receipts with a real JSON serializer, never string templating.","Include boolean-typed smoke checks in emitter unit tests."],"tags":["validation","json","types","provenance"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}