{"record":{"id":"6390a6cd4c3a3194","repo":"mvanhorn/last30days-skill","slug":"no-discovery-nominations-bundle-found-searched-n","errorCode":null,"errorMessage":"No discovery nominations bundle found. Searched:\\n{_searched_lines(searched)}\\n{_RESWEEP_REMEDY}","messagePattern":"No discovery nominations bundle found\\. Searched:\\\\n(.+?)\\\\n(.+?)","errorType":"exception","errorClass":"HandoffContractError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/discovery_handoff.py","lineNumber":374,"sourceCode":"    )\n\n\ndef read_nominations_bundle(\n    *,\n    save_dir: str | Path | None = None,\n    config_dir: Path | None = None,\n) -> NominationsBundle:\n    \"\"\"Locate and parse the nominations bundle for legs 2 and 3.\n\n    The bundle lives in the save dir when one was supplied, else the config\n    dir - never both (no cross-store fallback). Raises HandoffContractError\n    (naming the searched location and the re-sweep remedy) when no bundle\n    exists, and for any top-level contract violation in the file found.\n    \"\"\"\n    searched = _search_paths(save_dir, config_dir, nominations_bundle_path)\n    path = next((candidate for candidate in searched if candidate.exists()), None)\n    if path is None:\n        raise HandoffContractError(\n            \"No discovery nominations bundle found. Searched:\\n\"\n            f\"{_searched_lines(searched)}\\n{_RESWEEP_REMEDY}\"\n        )\n    return _parse_bundle_file(path)\n\n\ndef _parse_handoff_envelope(\n    path: Path,\n    *,\n    label: str,\n    kind: str,\n    schema_version: str,\n    remedy: str,\n    missing_id_context: str,\n    stale_context: str,\n) -> tuple[dict[str, Any], str, Any]:\n    \"\"\"Shared strict top-level validation for the two engine-written handoff\n    files (nominations bundle, pending report): readable, valid JSON object,","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/discovery_handoff.py#L356-L392","documentation":"`load_nominations_bundle` raises HandoffContractError (exit 2) when no `discover-nominations.json` exists in any searched location. Search is strict: the save dir when `--save-dir` was supplied, else the config dir — never a cross-store fallback. The message lists the exact paths searched and appends the re-sweep remedy ('Run a fresh `--discover --nominate-only` re-sweep').","triggerScenarios":"Invoking leg 2 (`--discover --judgments <file>`) before ever running leg 1; running leg 1 with `--save-dir A` and leg 2 with `--save-dir B` or no save dir; running leg 2 on a machine/container that never saw the bundle.","commonSituations":"Multi-step protocol split across sessions where leg 1 ran in a different directory or host; agents resuming a discovery run in a fresh sandbox; the user deleting/`clean`ing the save dir between legs.","solutions":["Run leg 1 first: `--discover --nominate-only`, and use the SAME `--save-dir` (or same config dir) for every subsequent leg.","Verify the file exists at the path printed in 'Searched:' — it should be `discover-nominations.json` inside that dir.","If the bundle is genuinely absent (new machine, cleaned dir), re-run the nominate-only sweep to regenerate it, then re-author judgments against the new bundle_id.","Do not hand-copy the bundle to another store hoping for fallback — resolution is save-dir-else-config-dir by design."],"exampleFix":"# before\npython3 last30days.py \"topic\" --discover --judgments judgments.json   # no leg 1 ever ran\n# after\npython3 last30days.py \"topic\" --discover --nominate-only --save-dir /tmp/run\npython3 last30days.py \"topic\" --discover --judgments judgments.json --save-dir /tmp/run","handlingStrategy":"validation","validationCode":"from pathlib import Path\nfrom lib.discovery_handoff import nominations_bundle_path, handoff_state_dir\n\nstate = handoff_state_dir(save_dir, config_dir)\nif state is None or not nominations_bundle_path(state).exists():\n    raise SystemExit(\"run `--discover --nominate-only` first in this store\")","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    sys.stderr.write(exc.message + \"\\n\")\n    sys.exit(2)","preventionTips":["Pin all legs of one protocol to one --save-dir; record it in your run notes or a wrapper script.","After leg 1, verify discover-nominations.json exists before authoring judgments.","Remember there is no cross-store fallback by design — the same store must be used every leg."],"tags":["discovery","handoff","protocol-state","exit-code-2"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}