debug(vp): env-flagged bridge-synthesised reply trace for slicer↔printer #1622 round-3 triage

Round-2 cmd.jsonl from shaddowlink proves the bridge forwards both commands and
  responses correctly: ams_filament_setting round-trips with result=success on P1S,
  the cached push_status carries tray_info_idx=GFA11/tray_type=PLA-AERO/K-n/cali_idx
  intact, and the visible "unload" symptom comes from the slicer's choice of
  extrusion_cali_set (push K direct, P1S firmware rejects) vs extrusion_cali_sel
  (select by id, both H2D and P1S accept). The open question is what makes the
  slicer pick _set vs _sel — likely the info.get_version response Bambuddy
  synthesises or the first cached pushall reply the slicer reads at connect.
  Round 2 captured neither; the JSONL had slicer_to_bridge and printer_to_slicer
  but no direction for the bridge's own synthesised replies.

  Same BAMBUDDY_VP_DUMP_WIRE=1 flag now also appends a bridge_to_slicer line for
  every bridge-synthesised reply (info.get_version answer, project_file ack,
  on-demand pushall response). Capture is in _publish_to_report — the single
  chokepoint — gated on a new log_event param; the 1Hz periodic push threads
  log_event=False so the JSONL isn't flooded (~60 lines/min/VP) because
  dump_wire already covers cache shape per tick.

  Diagnostic-only, no data-path change. Default param preserves every existing
  call site's behaviour.
This commit is contained in:
maziggy
2026-06-11 15:09:24 +02:00
parent 6b477088a2
commit 5644f11495
4 changed files with 98 additions and 16 deletions
+17 -10
View File
@@ -10,12 +10,15 @@ Set ``BAMBUDDY_VP_DUMP_WIRE=1`` to enable two complementary capture modes:
``*_in.json`` and ``*_out.json`` for the failing VP against a known-good
one (e.g. H2D vs P1S).
2. ``append_event``: time-ordered JSONL log of every slicer↔printer command
payload that flows through the VP (excludes the cached-as-base 1Hz push,
which dump_wire already covers). Triages command-flow bugs (e.g. #1622
round 2) where the cached state looks right but a slicer-initiated
write (ams_filament_setting / extrusion_cali_set / xcam / system) ends
up corrupting state. One line per event with wall-clock timestamp.
2. ``append_event``: time-ordered JSONL log of every slicer↔bridge↔printer
command payload that flows through the VP (excludes the cached-as-base
1Hz push, which dump_wire already covers). Triages command-flow bugs
(e.g. #1622 round 2 / round 3) where the cached state looks right but a
slicer-initiated write (ams_filament_setting / extrusion_cali_set /
xcam / system) ends up corrupting state, or where the slicer's choice
of command flow depends on what the bridge replies to its initial
info.get_version / pushall probe. One line per event with wall-clock
timestamp.
Layout:
- snapshot: ``<log_dir>/vp_wire/<sanitized_vp_name>_<direction>.json``
@@ -100,10 +103,14 @@ def append_event(vp_name: str, direction: str, topic: str, payload: dict | bytes
"""Append one event line to ``<log_dir>/vp_wire/<vp_name>_cmd.jsonl``.
No-op when the env flag is unset. ``direction`` should be one of
``"slicer_to_bridge"`` or ``"printer_to_slicer"`` so a diff between
a working VP and a broken VP can be read top-to-bottom in causal order.
Bytes payloads are utf-8 decoded then json-parsed best-effort; un-parseable
payloads are logged as ``{"raw": "<text>"}`` so the line is still valid JSON.
``"slicer_to_bridge"`` (slicer-originated publish reaching the bridge),
``"printer_to_slicer"`` (real-printer response fanned out to the slicer),
or ``"bridge_to_slicer"`` (bridge-synthesised reply: info.get_version
answer, project_file ack, on-demand pushall response). A diff between
a working VP and a broken VP can then be read top-to-bottom in causal
order. Bytes payloads are utf-8 decoded then json-parsed best-effort;
un-parseable payloads are logged as ``{"raw": "<text>"}`` so the line
is still valid JSON.
"""
if not _enabled():
return