Hmbown/CodeWhale · error · RuntimeContractError

field ` ` must match the owned sorted tool_names

Error message

{kind} field `{'.'.join((*base, 'identity_sha256'))}` must match the owned sorted tool_names

What it means

Each mode/surface section stores identity_sha256, the SHA-256 of its sorted tool_names joined with NUL bytes (see tool_identity_digest). If the stored digest does not match the recomputed value, the section's tool list was altered after signing or the digest was computed differently.

Solutions

  1. Recompute the digest with hashlib.sha256("\0".join(sorted(set(names))).encode()).hexdigest() and store it
  2. Regenerate the receipt with the current script so list and digest are consistent
  3. Ensure any external generator replicates the exact NUL-joined sorted-name hashing scheme

Example fix

# before (stale digest)
"identity_sha256": "aaa..."
# after
import hashlib
"identity_sha256": hashlib.sha256("\0".join(names).encode()).hexdigest()
Defensive patterns

Strategy: validation

Validate before calling

import hashlib
names = sorted(set(section["tool_names"]))
expected = hashlib.sha256("\0".join(names).encode("utf-8")).hexdigest()
assert section["identity_sha256"] == expected

Try / catch

try:
    validate_receipt(receipt)
except RuntimeContractError as e:
    if "must match the owned sorted tool_names" in str(e):
        print("stale identity digest; regenerate the receipt")
    raise

Prevention

When it happens

Trigger: validate_identity_structure recomputes tool_identity_digest(names) and finds it differs from the stored tool_catalog.modes.<mode>.<surface>.identity_sha256.

Common situations: tool_names edited without recomputing the digest; digest computed over unsorted or differently joined names by a custom generator; receipt copied from a different catalog state.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/278c6ca765f215bb. Report an issue: GitHub.

Appendix: source

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

            dotted_names = ".".join((*base, "tool_names"))
            if (
                not isinstance(names, list)
                or any(not isinstance(name, str) or not name for name in names)
                or names != sorted(set(names))
            ):
                raise RuntimeContractError(
                    f"{kind} field `{dotted_names}` must be sorted unique non-empty strings"
                )
            count = metric_value(document, (*base, "tools"), kind)
            if count != len(names):
                raise RuntimeContractError(
                    f"{kind} metric `{'.'.join((*base, 'tools'))}` must equal the "
                    f"owned tool_names length ({len(names)})"
                )
            digest = required_value(document, (*base, "identity_sha256"), kind)
            expected = tool_identity_digest(names)
            if digest != expected:
                raise RuntimeContractError(
                    f"{kind} field `{'.'.join((*base, 'identity_sha256'))}` must "
                    "match the owned sorted tool_names"
                )

    for stage, _label in REPRESENTATIVE_STAGES:
        path = ("representative_context", "stages", stage, "identity_sha256")
        digest = required_value(document, path, kind)
        if not isinstance(digest, str) or re.fullmatch(r"[0-9a-f]{64}", digest) is None:
            raise RuntimeContractError(
                f"{kind} field `{'.'.join(path)}` must be a lowercase SHA-256 digest"
            )


def validate_receipt(receipt: dict[str, Any]) -> None:
    validate_document(receipt, RECEIPT_KIND, "receipt")
    skill_discovery = receipt.get("skill_discovery")
    identical = (
        skill_discovery.get("prompts_byte_identical")

View on GitHub (pinned to 433685b202)