{"record":{"id":"5e79bce83303bb19","repo":"mvanhorn/last30days-skill","slug":"label-path-is-missing-its-bundle-id-missing","errorCode":null,"errorMessage":"{label} {path} is missing its bundle_id; {missing_id_context}. {remedy}","messagePattern":"(.+?) (.+?) is missing its bundle_id; (.+?)\\. (.+?)","errorType":"exception","errorClass":"HandoffContractError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/discovery_handoff.py","lineNumber":426,"sourceCode":"        raise HandoffContractError(\n            f\"{label} {path} must be a top-level JSON object, \"\n            f\"got {type(payload).__name__}.\"\n        )\n    version = payload.get(\"schema_version\")\n    if version != schema_version:\n        raise HandoffContractError(\n            f\"{label} {path} has schema version {version!r}; this \"\n            f\"build reads {schema_version!r}. {remedy}\"\n        )\n    file_kind = payload.get(\"kind\")\n    if file_kind != kind:\n        raise HandoffContractError(\n            f\"{label} {path} has kind {file_kind!r}; expected \"\n            f\"{kind!r}. {remedy}\"\n        )\n    bundle_id = str(payload.get(\"bundle_id\") or \"\")\n    if not bundle_id:\n        raise HandoffContractError(\n            f\"{label} {path} is missing its bundle_id; \"\n            f\"{missing_id_context}. {remedy}\"\n        )\n    generated_at = payload.get(\"generated_at\")\n    if not env.is_timestamp_fresh(generated_at, DISCOVERY_HANDOFF_TTL_SECONDS):\n        raise HandoffContractError(\n            f\"{label} {path} is stale (generated_at=\"\n            f\"{generated_at!r}, TTL {int(DISCOVERY_HANDOFF_TTL_SECONDS)}s): \"\n            f\"{stale_context}. {remedy}\"\n        )\n    return payload, bundle_id, generated_at\n\n\ndef _parse_bundle_file(path: Path) -> NominationsBundle:\n    payload, bundle_id, generated_at = _parse_handoff_envelope(\n        path,\n        label=\"Nominations bundle\",\n        kind=schema.DISCOVERY_NOMINATIONS_KIND,","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/discovery_handoff.py#L408-L444","documentation":"`_parse_handoff_envelope` raises HandoffContractError when the payload object has no non-empty `bundle_id`. The bundle_id is the join key of the whole three-leg protocol: leg-2 host judgments and the leg-3 pending report must bind to the exact bundle the sweep produced, so an envelope without one cannot participate. The message includes per-artifact context ('angles cannot bind to it' for pending reports) and the matching remedy.","triggerScenarios":"A hand-edited or reconstructed handoff file where `bundle_id` was dropped, set to null, or set to \"\"' — for example rebuilding a 'similar' bundle from a template, or a jq rewrite that lost the field.","commonSituations":"Attempting to reuse a previous run's bundle by editing its contents; partial corruption that kept valid JSON but shed fields; a model/host authoring a bundle by hand instead of running leg 1.","solutions":["Do not hand-author handoff files — regenerate with `--discover --nominate-only` so a fresh bundle_id is issued.","Check `jq .bundle_id <path>`; if empty/missing the file is not salvageable as-is.","After regenerating, re-author judgments: their bundle_id must match the NEW bundle's id (leg 2 reads the bundle and validates binding)."],"exampleFix":"# before: hand-built bundle lacking bundle_id\n# after\npython3 last30days.py \"topic\" --discover --nominate-only --save-dir /tmp/run   # engine writes bundle_id like a1b2c3d4e5f6a7b8","handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\n\ndef has_bundle_id(path: Path) -> bool:\n    try:\n        return bool(json.loads(path.read_text(encoding=\"utf-8\")).get(\"bundle_id\"))\n    except (OSError, json.JSONDecodeError):\n        return False","typeGuard":null,"tryCatchPattern":"from lib import discovery_handoff\ntry:\n    bundle = discovery_handoff.load_nominations_bundle(save_dir=save_dir, config_dir=config_dir)\nexcept discovery_handoff.HandoffContractError as exc:\n    if \"bundle_id\" in exc.message:\n        # unbindable state: regenerate the bundle and re-author judgments\n        ...","preventionTips":["Always take the bundle_id from the engine-written bundle (jq .bundle_id) when authoring judgments.","Never reconstruct a bundle by hand — the id is a 16-hex-char engine-issued token, not derivable."],"tags":["discovery","handoff","bundle-id","schema","exit-code-2"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}