Hmbown/CodeWhale · error · RuntimeContractError

receipt and budget must resolve to distinct filesystem paths

Error message

receipt and budget must resolve to distinct filesystem paths

What it means

main() refuses to run when --receipt and --budget resolve (Path.resolve()) to the same file. Comparing a receipt against itself would trivially pass every ceiling, and combined with --update the tool would overwrite the receipt with budget JSON, destroying the measurement evidence. Symlinks and './' versus absolute spellings of the same file are caught because resolve() normalizes them.

Source

Thrown at scripts/check-runtime-contract-budget.py:635

        help="check an existing measurement JSON instead of compiling",
    )
    parser.add_argument(
        "--budget",
        type=Path,
        default=BUDGET_PATH,
        help=argparse.SUPPRESS,
    )
    parser.add_argument(
        "--update",
        action="store_true",
        help="tighten all ceilings to the current receipt; refuses increases",
    )
    args = parser.parse_args(argv)

    try:
        check_fragment_caps()
        if args.receipt is not None and args.receipt.resolve() == args.budget.resolve():
            raise RuntimeContractError(
                "receipt and budget must resolve to distinct filesystem paths"
            )
        budget = load_json(args.budget, "budget")
        receipt = (
            load_json(args.receipt, "receipt")
            if args.receipt is not None
            else run_measurement()
        )
        increases, decreases = compare(receipt, budget)
    except RuntimeContractError as error:
        print(f"[runtime-contract-budget] ERROR: {error}", file=sys.stderr)
        return 2

    if increases:
        print("[runtime-contract-budget] FAIL: runtime contract grew:", file=sys.stderr)
        for path, label, current, ceiling in increases:
            print(
                f"  {label}: {current} > {ceiling} (+{current - ceiling}) [{path}]",

View on GitHub (pinned to 8880682c63)

Solutions

  1. Pass distinct files: keep the budget at scripts/runtime-contract-budget.json and point --receipt at a freshly measured receipt from measure-runtime-contract.py
  2. If aliasing was accidental (symlink or relative-path normalization), pass the real distinct paths
  3. In wrapper scripts, assert Path(receipt).resolve() != Path(budget).resolve() before invoking the checker

Example fix

# before
python3 scripts/check-runtime-contract-budget.py --receipt scripts/runtime-contract-budget.json

# after
python3 scripts/measure-runtime-contract.py > /tmp/receipt.json
python3 scripts/check-runtime-contract-budget.py --receipt /tmp/receipt.json
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
receipt, budget = Path(args.receipt), Path(args.budget)
assert receipt.resolve() != budget.resolve(), "receipt and budget must be distinct files"

Type guard

def is_runtime_contract_error(exc: BaseException) -> bool:
    return isinstance(exc, ValueError) and type(exc).__name__ == "RuntimeContractError"

Try / catch

try:
    rc = main(["--receipt", str(receipt)])
except RuntimeContractError as error:
    print(f"[gate] {error}", file=sys.stderr)
    raise SystemExit(2)

Prevention

When it happens

Trigger: '--receipt scripts/runtime-contract-budget.json' (identical to the default budget path); '--receipt r.json --budget r.json'; a symlinked receipt pointing at the budget file.

Common situations: Copy-pasting commands from docs; scripted invocations that reuse one path variable for both flags; passing a copied budget as a 'receipt' to skip measuring.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/362646183380008b. Report an issue: GitHub.