Summary
per_claim[i].indexed_at_path in the evaluate_handoff verdict is documented as the value extracted at the claim's json_path. Most of the time it's the parsed value (string, int, dict, list — whatever lives at the path). Occasionally it comes back as a JSON-encoded string of that value, e.g.:
indexed_at_path = '[{"created_at": "2026-04-12T15:30:00Z", "id": "ord_acme_002", ...}]'
— a string that contains the JSON, rather than the list itself.
Why this matters for consumers
Heal loops typically substitute indexed_at_path into the answer (heal_actions.py — see _short_primitive). When the leaf is a primitive it's safe to inline; when it's complex we skip. The string-encoded form fails that isinstance(leaf, (str, int, float)) check the wrong way: it looks primitive but is actually a JSON blob, so the substitution dumps a giant JSON string into the prose.
We patched it consumer-side by also rejecting strings that start with [ or { — but the heuristic is fragile, and it shouldn't be needed.
Proposed fix
indexed_at_path should always be the parsed value the SDK actually walked to. If the value happens to be a string, it should be a real string; if it's a list, a real list. The encoded shape suggests something like json.dumps is happening on a particular code path that should be reading the parsed structure directly.
If there's a deliberate reason (size limit, transport constraint), it should be:
- Documented in the verdict schema, and
- Consistently applied (always-string or always-parsed), so consumers don't have to type-sniff.
Summary
per_claim[i].indexed_at_pathin theevaluate_handoffverdict is documented as the value extracted at the claim'sjson_path. Most of the time it's the parsed value (string, int, dict, list — whatever lives at the path). Occasionally it comes back as a JSON-encoded string of that value, e.g.:— a string that contains the JSON, rather than the list itself.
Why this matters for consumers
Heal loops typically substitute
indexed_at_pathinto the answer (heal_actions.py — see_short_primitive). When the leaf is a primitive it's safe to inline; when it's complex we skip. The string-encoded form fails thatisinstance(leaf, (str, int, float))check the wrong way: it looks primitive but is actually a JSON blob, so the substitution dumps a giant JSON string into the prose.We patched it consumer-side by also rejecting strings that start with
[or{— but the heuristic is fragile, and it shouldn't be needed.Proposed fix
indexed_at_pathshould always be the parsed value the SDK actually walked to. If the value happens to be a string, it should be a real string; if it's a list, a real list. The encoded shape suggests something likejson.dumpsis happening on a particular code path that should be reading the parsed structure directly.If there's a deliberate reason (size limit, transport constraint), it should be: