Summary
evaluate_state_requirements reconstructs the final DB snapshot from the task-env
file, which stores entities as lists. scoring.py::_record_identity derives a
record's key from the first matching id field, but it checks owner/foreign keys
(order_id, customer_id, cart_id) before the record's own id (item_id,
…). An order_item carries both item_id and its parent order_id, so all line
items in the same order collapse under one key — only the last survives and its
siblings disappear from the reconstructed snapshot. Their state_requirements
then report as missing_assertions, failing the task even when the agent behaved
perfectly.
Environment
- STATE-Bench
v0.7.1 (commit a0ffc65)
state_bench/scoring.py, function _record_identity (around line 206)
Reproduction
Run from a STATE-Bench checkout (uses only shipped files — task
customer_support/13-cancel_partial):
import json
from pathlib import Path
from state_bench.scoring import _record_identity, evaluate_state_requirements
from state_bench.schemas import TaskDefinition, StateDiff
# Root cause: three sibling order_items collapse to one key.
items = [{"item_id": f"ITEM-{n}", "order_id": "ORD-1", "item_status": "confirmed"} for n in (1, 2, 3)]
print([_record_identity(i) for i in items]) # -> ['ORD-1', 'ORD-1', 'ORD-1']
# End-to-end: a correct partial cancellation of only the shirt (ITEM-9105).
task = TaskDefinition.from_dict(json.loads(
Path("state_bench/domains/customer_support/tasks/13-cancel_partial.json").read_text()))
state_diff = StateDiff(modified={
"orders": {"ORD-6016": {"status": {"old": "processing", "new": "partially_cancelled"}}},
"order_items": {"ITEM-9105": {
"item_status": {"old": "confirmed", "new": "cancelled"},
"refund_amount": {"old": None, "new": 59},
"refund_method": {"old": None, "new": "credit_card"},
}},
})
res = evaluate_state_requirements(task, state_diff)
print(res.score, res.reasoning, res.details)
Actual output (v0.7.1)
['ORD-1', 'ORD-1', 'ORD-1']
0 State requirements failed: missing_assertions=2 {'missing_assertions': [
{'entity_type': 'order_items', 'record_key': 'ITEM-9106', 'field': 'item_status', 'value': 'confirmed'},
{'entity_type': 'order_items', 'record_key': 'ITEM-9107', 'field': 'item_status', 'value': 'confirmed'}]}
ITEM-9106 and ITEM-9107 are never modified by the agent and should remain
confirmed, but they vanish from the reconstructed snapshot because all three
items collapsed under ORD-6016.
Expected output
['ITEM-1', 'ITEM-2', 'ITEM-3']
1 All required state assertions matched the saved state_diff. None
Impact
Any task asserting state on a sibling line item that is not the last in its order
gets phantom missing_assertions and a false task_completion = 0. Observed on
at least customer_support/13-cancel_partial and 15-cancel_backordered. The
same class affects orders keyed by customer_id for customers with multiple
orders (currently masked when the task modifies the order, so the diff re-adds the
correct key).
Suggested fix
Order _record_identity so a record's own id precedes owner/foreign keys.
Records without their own id (orders, customers, products) keep their previous
keying; only records that have both their own id and a parent id change:
def _record_identity(record: dict[str, Any], fallback_index: int | None = None) -> str | None:
for key in (
"cart_item_id",
- "cart_id",
- "customer_id",
- "order_id",
"item_id",
"booking_id",
"reservation_id",
"rental_id",
+ "cart_id",
+ "order_id",
+ "customer_id",
"id",
"product_id",
):
Summary
evaluate_state_requirementsreconstructs the final DB snapshot from the task-envfile, which stores entities as lists.
scoring.py::_record_identityderives arecord's key from the first matching id field, but it checks owner/foreign keys
(
order_id,customer_id,cart_id) before the record's own id (item_id,…). An
order_itemcarries bothitem_idand its parentorder_id, so all lineitems in the same order collapse under one key — only the last survives and its
siblings disappear from the reconstructed snapshot. Their
state_requirementsthen report as
missing_assertions, failing the task even when the agent behavedperfectly.
Environment
v0.7.1(commita0ffc65)state_bench/scoring.py, function_record_identity(around line 206)Reproduction
Run from a STATE-Bench checkout (uses only shipped files — task
customer_support/13-cancel_partial):Actual output (v0.7.1)
ITEM-9106andITEM-9107are never modified by the agent and should remainconfirmed, but they vanish from the reconstructed snapshot because all threeitems collapsed under
ORD-6016.Expected output
Impact
Any task asserting state on a sibling line item that is not the last in its order
gets phantom
missing_assertionsand a falsetask_completion = 0. Observed onat least
customer_support/13-cancel_partialand15-cancel_backordered. Thesame class affects
orderskeyed bycustomer_idfor customers with multipleorders (currently masked when the task modifies the order, so the diff re-adds the
correct key).
Suggested fix
Order
_record_identityso a record's own id precedes owner/foreign keys.Records without their own id (orders, customers, products) keep their previous
keying; only records that have both their own id and a parent id change:
def _record_identity(record: dict[str, Any], fallback_index: int | None = None) -> str | None: for key in ( "cart_item_id", - "cart_id", - "customer_id", - "order_id", "item_id", "booking_id", "reservation_id", "rental_id", + "cart_id", + "order_id", + "customer_id", "id", "product_id", ):