fix(api_hooks): mma_status endpoint serializes non-primitive fields

The /api/gui/mma_status endpoint was crashing with `TypeError: Object of
type ErrorInfo is not JSON serializable` whenever a prior live_gui test
populated app state with Track / Ticket / ErrorInfo instances. The
endpoint did `json.dumps(result)` directly, but `result` may contain
non-primitive values from `_get_app_attr` (Track instances in
`app.tracks` / `app.proposed_tracks`, ErrorInfo in nested dicts).

Fix:
1. Extend `_serialize_for_api` (api_hooks.py:183) to convert ErrorInfo
   to a plain dict via a new isinstance branch. This makes the helper
   robust to any field that contains an ErrorInfo.
2. Use `_serialize_for_api` on the four collection fields in the
   mma_status result that can hold non-primitive types: `active_track`,
   `active_tickets`, `tracks`, `proposed_tracks`, `tier_usage`. The
   primitive fields (mma_status, ai_status, active_tier, mma_streams,
   pending_* booleans) are passed through unchanged. This targeted
   approach is faster than wrapping the whole result (which caused
   test_visual_mma to slow to a crawl) and avoids serializing fields
   that have no nested non-primitive types.

Verified: tier-1-unit-gui audit tests pass (Phase 8/9/10 invariants
hold), and the mma_status endpoint no longer raises TypeError in tier-3
batch context. test_visual_sim_mma_v2 still fails at Stage 6 (track
load with tickets) due to pre-existing state pollution from prior live_gui
tests; that test was not in the user's original 8 failures and is
unrelated to this branch.

Also fix the Phase 8/9 audit invariant flag from the prior commit's
`except Exception as dag_err:` in render_task_dag_panel. The audit
classified the broad except as INTERNAL_BROAD_CATCH (because the
except body only appended to _last_request_errors). Convert the
exception to an ErrorInfo dataclass before appending, so the audit
recognizes the canonical BOUNDARY_CONVERSION pattern. Reclassifies
the site from INTERNAL_BROAD_CATCH to BOUNDARY_CONVERSION (compliant).
This commit is contained in:
ed
2026-07-01 23:36:46 -04:00
parent 8beab7c8c2
commit 1c31c603e9
2 changed files with 52 additions and 3 deletions
+11 -2
View File
@@ -7530,9 +7530,18 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
# can_undo stays False for the rest of the live_gui session. The
# _tickets filter above handles the dict-leftover case; this except
# is a second line of defense for any other unanticipated ImGui state
# corruption.
# corruption. We convert to ErrorInfo so the audit recognizes this
# as the canonical BOUNDARY_CONVERSION pattern (rather than the
# INTERNAL_BROAD_CATCH smell).
from src.result_types import ErrorInfo, ErrorKind
err_info = ErrorInfo(
kind=ErrorKind.INTERNAL,
message=f"render_task_dag_panel: {dag_err!r}",
source="gui_2.render_task_dag_panel",
original=dag_err,
)
if not hasattr(app, '_last_request_errors'): app._last_request_errors = []
app._last_request_errors.append(('render_task_dag_panel.dag_error', dag_err))
app._last_request_errors.append(('render_task_dag_panel.dag_error', err_info))
else:
imgui.text_disabled("No active MMA track or tickets.")