{"record":{"id":"cb0a672ccf1acf84","repo":"nexu-io/open-design","slug":"job-job-id-has-invalid-secondary-fallback-proven","errorCode":null,"errorMessage":"job {job_id} has invalid secondary fallback provenance","messagePattern":"job (.+?) has invalid secondary fallback provenance","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"skills/hatch-pet/scripts/finalize_pet_run.py","lineNumber":154,"sourceCode":"        if job.get(flag)\n    ]\n    if blocked_flags:\n        raise SystemExit(\n            f\"job {job_id} was marked as a local/synthetic row ({', '.join(blocked_flags)}); \"\n            \"regenerate it with $imagegen\"\n        )\n\n    if job.get(\"synthetic_test_source\"):\n        if not allow_synthetic_test_sources:\n            raise SystemExit(\n                f\"job {job_id} uses a synthetic test source; rerun with real $imagegen output\"\n            )\n        validate_hash(job, source=source, output=output, job_id=job_id)\n        return\n\n    if job.get(\"secondary_fallback\"):\n        if job.get(\"source_provenance\") != \"secondary-fallback-image-api\":\n            raise SystemExit(f\"job {job_id} has invalid secondary fallback provenance\")\n        validate_hash(job, source=source, output=output, job_id=job_id)\n        return\n\n    if job.get(\"source_provenance\") == \"deterministic-mirror\":\n        validate_mirror_hash(job, source=source, output=output, job_id=job_id)\n        return\n\n    if job.get(\"source_provenance\") != \"built-in-imagegen\":\n        raise SystemExit(\n            f\"job {job_id} was not recorded as a built-in $imagegen output; \"\n            \"use record_imagegen_result.py with the selected $CODEX_HOME/generated_images/.../ig_*.png file\"\n        )\n    if is_relative_to(source, run_dir):\n        raise SystemExit(\n            f\"job {job_id} source image is inside the pet run directory; \"\n            \"do not use locally generated row artifacts as visual sources\"\n        )\n    generated_root = default_generated_images_root()","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/skills/hatch-pet/scripts/finalize_pet_run.py#L136-L172","documentation":"Raised by validate_completed_job_source when a job has secondary_fallback truthy but source_provenance != 'secondary-fallback-image-api'. The two fields must agree: a secondary-fallback row is one generated through generate_pet_images.py's OpenAI image API fallback, which sets both fields together via complete_job().","triggerScenarios":"job['secondary_fallback'] is truthy while job['source_provenance'] is something else (or missing). Caused by manually toggling secondary_fallback without updating provenance, or a partial write from complete_job().","commonSituations":"Editing imagegen-jobs.json to force a row through the fallback path; an interrupted generate_pet_images.py run that set secondary_fallback but did not yet set source_provenance.","solutions":["Re-run generate_pet_images.py for that job so complete_job() writes both secondary_fallback and source_provenance='secondary-fallback-image-api' atomically.","Manually align the two fields in imagegen-jobs.json only if you understand the contract.","Prefer regenerating with the real $imagegen built-in path (source_provenance='built-in-imagegen') to avoid the fallback entirely."],"exampleFix":"// before (imagegen-jobs.json)\n{\"id\":\"waving\",\"secondary_fallback\":true,\"source_provenance\":\"built-in-imagegen\"}\n// after\n{\"id\":\"waving\",\"secondary_fallback\":true,\"source_provenance\":\"secondary-fallback-image-api\"}","handlingStrategy":"validation","validationCode":"if job.get('secondary_fallback') and job.get('source_provenance') != 'secondary-fallback-image-api':\n    raise RuntimeError(f'job {job[\"id\"]} secondary_fallback/provenance mismatch')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Let generate_pet_images.py's complete_job() set secondary_fallback and provenance together.","Never toggle one field without the other when editing the manifest.","Prefer the built-in $imagegen path to avoid the fallback entirely."],"tags":["manifest","provenance","secondary-fallback","pet-pipeline"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}