{"record":{"id":"145d7af4ac8e079b","repo":"affaan-m/ECC","slug":"modality-request-crosses-the-dry-run-boundary","errorCode":null,"errorMessage":"{modality} request crosses the dry-run boundary","messagePattern":"(.+?) request crosses the dry-run boundary","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"critical","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":304,"sourceCode":"    if missing:\n        raise ContractError(f\"missing modality manifests: {sorted(missing)}\")\n    for modality in _REQUIRED_MODALITIES:\n        payload = json.loads((manifests_dir / f\"{modality}.json\").read_text(encoding=\"utf-8\"))\n        if payload.get(\"modality\") != modality or not payload.get(\"requests\"):\n            raise ContractError(f\"invalid or empty {modality} manifest\")\n        if (payload.get(\"dry_run\") is not True or payload.get(\"submit\") is not False\n                or type(payload.get(\"provider_calls\")) is not int\n                or payload.get(\"provider_calls\") != 0\n                or payload.get(\"provider_execution\") is not False):\n            raise ContractError(f\"{modality} manifest crosses the dry-run boundary\")\n        for request in payload[\"requests\"]:\n            if (request.get(\"dry_run\") is not True\n                    or request.get(\"submit\") is not False\n                    or type(request.get(\"provider_calls\")) is not int\n                    or request.get(\"provider_calls\") != 0\n                    or request.get(\"provider_execution\") is not False\n                    or request.get(\"provider_call_mode\") != \"disabled\"):\n                raise ContractError(f\"{modality} request crosses the dry-run boundary\")\n\n\ndef validate_artifact_receipt(out_dir: str | Path, receipt: dict[str, Any]) -> None:\n    \"\"\"Verify that the receipt binds every emitted artifact and its provenance.\"\"\"\n    out_dir = Path(out_dir).resolve()\n    entries = receipt.get(\"evidence_artifacts\")\n    if not isinstance(entries, list):\n        raise ContractError(\"receipt evidence_artifacts must be a list\")\n    if not all(isinstance(entry, dict) for entry in entries):\n        raise ContractError(\"receipt evidence_artifacts entries must be objects\")\n    known_sources: set[tuple[str, str]] = set()\n    source_durations: dict[tuple[str, str], float] = {}\n    for key in (\"references\", \"evidence_files\"):\n        sources = receipt.get(key, [])\n        if not isinstance(sources, list):\n            raise ContractError(f\"receipt {key} must be a list\")\n        for source in sources:\n            if not isinstance(source, dict):","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L286-L322","documentation":"Every individual request inside a modality manifest must also obey the dry-run boundary: dry_run=true, submit=false, provider_calls int 0, provider_execution=false, and provider_call_mode='disabled'. A request violating any of these raises this ContractError.","triggerScenarios":"A request entry with dry_run=false; submit=true; provider_calls=1; provider_calls missing (None fails type check); provider_execution=true; or provider_call_mode set to 'single'/'batch' instead of 'disabled'.","commonSituations":"Requests copied from a live-execution example; forgetting to set provider_call_mode='disabled' (it is only checked here, not on the manifest); leaving per-request overrides enabled from a prior real run; template requests carrying provider flags that the manifest-level check does not cover.","solutions":["Set provider_call_mode='disabled' plus dry_run=true, submit=false, provider_execution=false, provider_calls=0 on every request in the manifest.","Audit each request object individually — the manifest may pass the boundary check while individual requests violate it.","Regenerate requests from the dry-run template instead of copying from live-run configurations.","Add a pre-commit or CI lint that rejects request objects with provider_call_mode != 'disabled'."],"exampleFix":"// before\nrequest = {\"dry_run\": true, \"submit\": false, \"provider_calls\": 0, \"provider_execution\": false, \"provider_call_mode\": \"single\"}\n// after\nrequest = {\"dry_run\": true, \"submit\": false, \"provider_calls\": 0, \"provider_execution\": false, \"provider_call_mode\": \"disabled\"}","handlingStrategy":"validation","validationCode":"def request_within_boundary(req):\n    return (req.get(\"dry_run\") is True\n            and req.get(\"submit\") is False\n            and type(req.get(\"provider_calls\")) is int\n            and req.get(\"provider_calls\") == 0\n            and req.get(\"provider_execution\") is False\n            and req.get(\"provider_call_mode\") == \"disabled\")\nassert all(request_within_boundary(r) for m in manifests for r in m[\"requests\"])","typeGuard":"def is_disabled_request(req: dict) -> bool:\n    return req.get(\"provider_call_mode\") == \"disabled\" and req.get(\"dry_run\") is True \\\n        and req.get(\"submit\") is False and req.get(\"provider_execution\") is False \\\n        and type(req.get(\"provider_calls\")) is int and req.get(\"provider_calls\") == 0","tryCatchPattern":"try:\n    validate_manifests(manifests_dir)\nexcept ContractError as e:\n    if \"request crosses the dry-run boundary\" in str(e):\n        sanitize_requests(manifests_dir)  # force provider_call_mode='disabled' etc.\n        validate_manifests(manifests_dir)\n    else:\n        raise","preventionTips":["Set provider_call_mode='disabled' explicitly on every request — the manifest-level check does not cover it.","Build requests from a single dry-run factory function so boundary flags are never omitted.","Lint request objects in CI for all five boundary conditions before bundling.","Never copy request objects from live-execution examples."],"tags":["dry-run","safety","provider","requests"],"backgroundTag":"conflicting-config-options","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}