Part of the "Typed payloads: parse, don't validate" milestone. Follows #416 / PR #417.
Problem — response side, not input side
_is_ai_automation_summary_row (ai_preflight.py) and cli/commands/ai_automation.py read listing rows with dual-alias branches:
ai_preflight.py: row.get("action_id") or row.get("actionId"), row.get("action_params") or row.get("actionParams")
cli/ai_automation.py: row.get("action_params") or row.get("actionParams"), action_params.get("aiParams") or action_params.get("ai_params"), ai_params.get("fieldIds") or ai_params.get("field_ids"), row.get("event_id") or row.get("eventId")
Unlike the input-side issues, the row shape is decided by our own query documents, not the API input schema. A dual-read means two query paths produce different key styles (e.g. one query aliases eventId: event_id, another does not).
Approach
- Find the query document(s) that produce these rows and canonicalize the selected key style (pick one — align with how the API returns them / how the SDK's other agent queries alias).
- Type the row with a small read-model (or reuse
automation_graphql_types.py), then read typed attributes.
- Delete the dual-reads.
Do the query alignment first; typing the row on top of two disagreeing queries just moves the problem.
Acceptance
- One canonical key style for AI-automation summary rows; dual-reads removed.
uv run pytest -m "not integration" + ruff + import-linter green.
Part of the "Typed payloads: parse, don't validate" milestone. Follows #416 / PR #417.
Problem — response side, not input side
_is_ai_automation_summary_row(ai_preflight.py) andcli/commands/ai_automation.pyread listing rows with dual-alias branches:ai_preflight.py:row.get("action_id") or row.get("actionId"),row.get("action_params") or row.get("actionParams")cli/ai_automation.py:row.get("action_params") or row.get("actionParams"),action_params.get("aiParams") or action_params.get("ai_params"),ai_params.get("fieldIds") or ai_params.get("field_ids"),row.get("event_id") or row.get("eventId")Unlike the input-side issues, the row shape is decided by our own query documents, not the API input schema. A dual-read means two query paths produce different key styles (e.g. one query aliases
eventId: event_id, another does not).Approach
automation_graphql_types.py), then read typed attributes.Do the query alignment first; typing the row on top of two disagreeing queries just moves the problem.
Acceptance
uv run pytest -m "not integration"+ ruff + import-linter green.