Skip to content

debugviewer: live-session sidebar + auto-attach + flashing fix; engine live-trace hoist; pipeline e2e fix - #3

Merged
moonexpr merged 4 commits into
betafrom
topic/debugviewer-elk-live-theme
Jul 9, 2026
Merged

moonexpr merged 4 commits into
betafrom
topic/debugviewer-elk-live-theme

Conversation

@moonexpr

@moonexpr moonexpr commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Combined debugviewer + engine work plus the pipeline e2e fix, landing together into beta.

debugviewer (viewer.html)

  • Stop the SVG flashing on auto-refresh — skip the redraw when the compiled graph is unchanged; keep a live run tracked across refreshes.
  • Surface live sessions in an always-visible panel at the top of the LEFT sidebar (above workflows); demote the in-process mock runner to a small fold.
  • Poll for external live runs unconditionally and auto-attach the newest actively-running one (⦿ auto toggle; manual click still works).
  • Draggable left-sidebar width handle mirroring the inspector's (double-click resets; width persisted).

engine (baseworkflow.py, websitewf.py, trace.py, bus.py)

  • Hoist the live-trace sidecar observer into BaseWorkflow.run so every engine — baseworkflow, websitewf, future overlays — is watchable with zero per-engine wiring.
  • FileObserver heartbeats its sidecar mtime every 15s so a live-but-quiet run (mid-inference) is not misread as dead; bus.py exposes mtime; the viewer treats a run as live only if status=running AND mtime is fresh.

pipeline

  • fix(pipeline): unblock live oneshot e2e — research dispatch, adapter, migrate (8b26629, @-other-agent).

Verified: heartbeat advances mtime while quiet and stops on finish; both engines emit correctly-labelled sidecars; JS parses; flashing eliminated on unchanged-YAML refresh.

moonexpr added 4 commits July 8, 2026 17:09
…acked

The header ● live auto-refresh (and ↻ refresh) redrew the whole graph every
3s unconditionally — svg.innerHTML='' + a full async ELK relayout — even when
the compiled graph was unchanged, which flashed the SVG. The same path also
ran stopStream(), so an attached live run stopped being tracked each cycle.

- Skip the redraw when the graph is unchanged: graphSig() signs nodes/edges/
  phases (deterministic for unchanged YAML) and refresh() only redraws on a
  real change, via the new non-destructive redrawCurrentWorkflow().
- refresh no longer tears down the SSE stream, so a live session stays tracked
  while auto-refresh is on (workflow switches still reset via selectWorkflow).
- Preserve run highlights across a legitimate redraw: RUN_VIS records each
  state's active/done class and applyRunVis() re-lights nodes after draw().
The live-trace sidecar (what makes a run watchable in the debug viewer) was
wired only in baseworkflow.run_live, so websitewf runs — a BaseWorkflow
subclass with its own run_live/_run — wrote no sidecar and were invisible to
the viewer. Wiring it per engine is engine plumbing leaking into consumer
overlays.

Attach the observer once in BaseWorkflow.run (inherited by every engine): when
tracing is enabled () and the caller supplied no
observer, attach a FileObserver labelled by the workflow's YAML stem
(WORKFLOW_PATH -> baseworkflow/websitewf, matching the viewer's graph names)
and finish only the observer we created. The in-process BusObserver path is
untouched (guarded by ctx.observer is None; the viewer finishes its own).

- Remove the now-redundant wiring from baseworkflow.run_live.
- Revert the copy from websitewf._run — it inherits BaseWorkflow.run.

Verified: baseworkflow + websitewf run_mock each emit a correctly-labelled
sidecar with a terminal status; the viewer picks up websitewf runs like
baseworkflow ones.
… migrate

Three defects surfaced by an end-to-end live run (the action.py stack dump from
the prior commit pinpointed each). With these the full spec→work→build tick
completes live and deploys.

- research.py: LIVE_INFERENCE_WORKERS was keyed "research_investigate" but
  ArchitectFactory dispatches by token.split(":")[-1] = "investigate", so the
  live FileResearcher/WebResearcher worker was never invoked — raw model prose
  hit the JSON adapter and failed the tick. Re-keyed to "investigate" (every
  other worker's bind name equals its token's last segment; research was the lone
  mismatch). The worker parses loosely and fail-safes to baseline.
- adapter.py: JsonAdapter.decode json.loads'd model output unguarded — empty
  output crashed with a bare JSONDecodeError. Now: empty -> {} (failures-as-data),
  fenced/prose-wrapped JSON salvaged, genuinely-garbled -> a HANDLED ActionError.
- admin.py: admin:migrate constructed _env.Environment() with no args, but the
  ctor requires `sources` — a TypeError that aborted the tick just before publish.
  Use Environment.default() (the canonical factory, as at admin.py:292/442).

Verified: live e2e green (ok=True) — engineer codegen builds, publish deploys to
Vercel, consolidate opens one PR, no-issue guard skips the label machine.
… resizable

Live runs were buried in a collapsed right-side 'mocked session' fold that only
polled while open, and attaching was a manual click — so a live session looked
invisible. Make a live session track itself:

- Move live sessions to a always-visible panel at the top of the LEFT sidebar,
  above the workflow list; demote the in-process mock runner to a small fold.
- Poll for external live runs unconditionally, and auto-attach the newest
  actively-running one (⦿ auto toggle to opt out; manual click still works).
- Add a draggable width handle to the left sidebar, mirroring the inspector's
  (double-click resets; width persisted).

Robust liveness, not a guess: a live run goes silent for minutes during long
inference/publish steps, so a plain mtime cutoff would call it dead. FileObserver
now heartbeats its sidecar's mtime every 15s (touch only, no extra lines) and
stops on finish(); bus.py exposes mtime; the viewer treats a run as live only if
status=running AND mtime is fresh (60s) — which also flags a sidecar whose writer
died (stuck at 'running') as dead instead of auto-attaching it.

Verified: heartbeat advances mtime while quiet and stops on finish; JS parses;
live endpoint carries mtime.
@moonexpr
moonexpr merged commit a019bc1 into beta Jul 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant