Hmbown/CodeWhale · error · RuntimeContractError
{kind} field `{'.'.join(path)}` must be a lowercase SHA-256
Error message
{kind} field `{'.'.join(path)}` must be a lowercase SHA-256 digest What it means
Each representative stage (base, project, instructions, skill, memory, goal, handoff) must store representative_context.stages.<stage>.identity_sha256 as a 64-character lowercase hex SHA-256 (re.fullmatch(r"[0-9a-f]{64}")). This is a format-only check - unlike error 202 it does not recompute the hash because the stage prompt is not part of the document. It guarantees the value can be compared byte-wise by compare()'s identity loop.
Source
Thrown at scripts/check-runtime-contract-budget.py:243
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")
if isinstance(skill_discovery, dict)
else None
)
if identical is not True:
raise RuntimeContractError(
"receipt metric `skill_discovery.prompts_byte_identical` must be true"
)
representative = receipt.get("representative_context")
fixture_id = (View on GitHub (pinned to 8880682c63)
Solutions
- Replace the value with the full 64-character lowercase hex digest of the stage's prompt bytes
- If the stage prompt legitimately changed, re-measure so the harness recomputes every stage digest, then record the new values in the budget as one decision
- Validate the file shape first: python3 -m json.tool scripts/runtime-contract-budget.json
Example fix
// before "identity_sha256": "E1BBB7A700C2ED6E..." // after - 64 lowercase hex chars, no prefix "identity_sha256": "e1bbb7a700c2ed6eea8d2aad15e60c86d0ac386f0583afc659cfc2527db8ce58"
Defensive patterns
Strategy: validation
Validate before calling
import re
STAGES = ("base", "project", "instructions", "skill", "memory", "goal", "handoff")
SHA256_RE = re.compile(r"[0-9a-f]{64}")
def stage_digests_wellformed(doc: dict) -> bool:
stages = doc.get("representative_context", {}).get("stages", {})
for stage in STAGES:
digest = stages.get(stage, {}).get("identity_sha256")
if not isinstance(digest, str) or SHA256_RE.fullmatch(digest) is None:
return False
return True Type guard
import re
def is_lowercase_sha256(value: object) -> bool:
return isinstance(value, str) and re.fullmatch(r"[0-9a-f]{64}", value) is not None Prevention
- Always copy full 64-char digests from measure output; never retype or truncate them
- Avoid `sha256:`-style prefixes in this file - the checker wants bare lowercase hex
- Validate edited budget files with a fullmatch regex before committing
When it happens
Trigger: A stage digest that is uppercase hex, shorter or longer than 64 chars, a placeholder like "TODO" or "sha256:...", a non-string (number/null), or a missing field surfaced through required_value and then type-checked here. Hit in validate_receipt/validate_budget/compare/budget_from_receipt.
Common situations: Hand-authoring a test receipt and stubbing digests; a git merge that truncates a line of the budget JSON; tooling that base64-encodes or prefixes digests (sha256:, git-style).
Related errors
- {kind} field `{'.'.join((*base, 'identity_sha256'))}` must m
- ${label} contains an invalid checksum row: ${trimmed}
- unit must be 'chars' or 'lines'
- max_chars must be > 0
- overlap must be smaller than max_chars
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/2e5b808ac3250d8c.
Report an issue: GitHub.