Hmbown/CodeWhale · error · RuntimeContractError
{kind} field `{dotted_names}` must be sorted unique non-empt
Error message
{kind} field `{dotted_names}` must be sorted unique non-empty strings What it means
Thrown by validate_identity_structure when validating either a measurement receipt or scripts/runtime-contract-budget.json. For every mode (plan/act/operate) and surface (full/active), tool_catalog.modes.<mode>.<surface>.tool_names must be a JSON array of non-empty strings that equals its own sorted(set(...)) - lexicographically sorted with no duplicates. The strictness makes the tool identity deterministic so the identity_sha256 digest and the ratchet comparison in compare() stay stable. It reaches the CLI as `[runtime-contract-budget] ERROR: ...` with exit code 2.
Source
Thrown at scripts/check-runtime-contract-budget.py:222
def validate_identity_structure(document: dict[str, Any], kind: str) -> None:
profile = required_value(document, ("tool_catalog", "surface_profile"), kind)
if profile != TOOL_SURFACE_PROFILE:
raise RuntimeContractError(
f"{kind} tool surface_profile must be `{TOOL_SURFACE_PROFILE}`, "
f"got {profile!r}"
)
for mode, _label in VISIBLE_MODES:
for surface, _surface_label in TOOL_SURFACES:
base = ("tool_catalog", "modes", mode, surface)
names = required_value(document, (*base, "tool_names"), kind)
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")View on GitHub (pinned to 8880682c63)
Solutions
- Sort and deduplicate the exact tool_names array named in the message (tool_catalog.modes.<mode>.<surface>.tool_names)
- Recompute identity_sha256 for that node, since the digest is taken over the sorted names (sha256 of NUL-joined list)
- If the name set legitimately changed, update names, tools count, bytes, tokens_est, and identity_sha256 together in scripts/runtime-contract-budget.json and justify it in _comment (the file's existing convention)
- Once compare() passes again, lock in the state with python3 scripts/check-runtime-contract-budget.py --update
Example fix
// before (scripts/runtime-contract-budget.json) "tool_names": ["read", "bash", "apply_patch"] // after - sorted, unique, non-empty "tool_names": ["apply_patch", "bash", "read"]
Defensive patterns
Strategy: validation
Validate before calling
def tool_names_wellformed(doc: dict) -> bool:
for mode in ("plan", "act", "operate"):
for surface in ("full", "active"):
node = (
doc.get("tool_catalog", {})
.get("modes", {})
.get(mode, {})
.get(surface, {})
)
names = node.get("tool_names")
if not isinstance(names, list):
return False
if any(not isinstance(n, str) or not n for n in names):
return False
if names != sorted(set(names)):
return False
return True
# before compare(receipt, budget) or run_measurement()
assert tool_names_wellformed(receipt) and tool_names_wellformed(budget) Prevention
- Never hand-edit tool_names in runtime-contract-budget.json; change the catalog in code and re-measure
- After any budget edit, run python3 -m json.tool scripts/runtime-contract-budget.json and the checker with --receipt on a known-good receipt
- Treat tool_names as generated data: the only sanctioned writer is the measure script plus --update
When it happens
Trigger: Any call to compare(), validate_receipt(), validate_budget(), budget_from_receipt(), or run_measurement() (the default no-argument CLI run) where a tool_names entry is not a string, is empty, is duplicated, or is out of order - e.g. ["read", "bash", "apply_patch"]. Almost always a hand-edited budget JSON or a receipt from an older scripts/measure-runtime-contract.py.
Common situations: Hand-adding a newly introduced tool (the v0.9.8 `agent` tool pattern recorded in the budget _comment) at the wrong position; resolving a merge conflict in runtime-contract-budget.json so names get reordered; a stale receipt checked with --receipt after the measure script changed its ordering.
Related errors
- baseline provenance build profile/sample count changed
- {kind} metric `{'.'.join((*base, 'tools'))}` must equal the
- invalid {label} {path}: {error}
- {label} must be a JSON object
- {field} must be a non-negative integer
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/d988d5b824e8d25e.
Report an issue: GitHub.