nexu-io/open-design · error · SystemExit
running-right must be complete before deriving running-left
Error message
running-right must be complete before deriving running-left
What it means
The mirror script refuses to derive running-left until the running-right imagegen job is fully done. It loads imagegen-jobs.json, finds the running-right job, and requires job["status"] == "complete". Mirroring an incomplete strip would bake an interim, blank, or failed image into the left sprite, which finalize_pet_run.py would later reject or, worse, ship.
Source
Thrown at skills/hatch-pet/scripts/derive_running_left_from_running_right.py:88
required=True,
help="Short note explaining why mirroring is acceptable for this pet.",
)
parser.add_argument("--force", action="store_true")
args = parser.parse_args()
if not args.confirm_appropriate_mirror:
raise SystemExit("refusing to mirror without --confirm-appropriate-mirror")
if not args.decision_note.strip():
raise SystemExit("--decision-note must explain why mirroring is appropriate")
run_dir = Path(args.run_dir).expanduser().resolve()
manifest_path = run_dir / "imagegen-jobs.json"
manifest = load_manifest(run_dir)
right_job = find_job(manifest, "running-right")
left_job = find_job(manifest, "running-left")
if right_job.get("status") != "complete":
raise SystemExit("running-right must be complete before deriving running-left")
mirror_policy = left_job.get("mirror_policy")
if not isinstance(mirror_policy, dict) or mirror_policy.get("may_derive_from") != "running-right":
raise SystemExit("running-left is not configured for conditional mirroring")
source = run_dir / "decoded" / "running-right.png"
output = run_dir / "decoded" / "running-left.png"
if not source.is_file():
raise SystemExit(f"running-right decoded strip not found: {source}")
if output.exists() and not args.force:
raise SystemExit(f"{output} already exists; pass --force to replace it")
output.parent.mkdir(parents=True, exist_ok=True)
with Image.open(source) as image:
mirrored = ImageOps.mirror(image.convert("RGBA"))
mirrored.save(output)
left_job["status"] = "complete"
left_job["source_path"] = manifest_relative(source, run_dir)View on GitHub (pinned to 5be4028344)
Solutions
- Inspect imagegen-jobs.json (or run pet_job_status.py --run-dir <dir>) and confirm the running-right job status reads "complete".
- If running-right is still pending/running, let $imagegen finish (or re-run it) until the job completes.
- If the image already exists on disk but the manifest is stale, run record_imagegen_result.py to record completion.
- Re-run derive_running_left_from_running_right.py once status is complete.
Defensive patterns
Strategy: validation
Validate before calling
import json
from pathlib import Path
run_dir = Path("<run_dir>")
manifest = json.loads((run_dir / "imagegen-jobs.json").read_text())
right = next(j for j in manifest["jobs"] if j.get("id") == "running-right")
if right.get("status") != "complete":
raise RuntimeError(f"running-right not complete: {right.get('status')!r}") Type guard
def right_job_ready(manifest: dict) -> bool:
job = next((j for j in manifest.get("jobs", []) if j.get("id") == "running-right"), None)
return isinstance(job, dict) and job.get("status") == "complete" Prevention
- Run derive_running_left_from_running_right.py only after pet_job_status.py shows running-right complete.
- Treat the imagegen → record → derive → finalize order as a hard pipeline; do not skip ahead.
- If a job is stuck, re-queue it rather than editing status by hand.
When it happens
Trigger: Running derive_running_left_from_running_right.py --run-dir <dir> while the running-right job's status is anything other than the literal "complete" (e.g. "pending", "running", "failed", "queued").
Common situations: Running the derive step out of order, before $imagegen finishes; a running-right job stuck in "running"; a job that errored but was never re-queued; reading a stale manifest copy.
Related errors
- job manifest not found: {path}
- invalid imagegen-jobs.json: jobs must be a list
- unknown job id: {job_id}
- running-left is not configured for conditional mirroring
- job {job_id} has no {field}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/87daeb97d7d87644.
Report an issue: GitHub.