-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Summary
The transcript recording system (window._buckarooTranscript, record_transcript trait, PinnedRowsTranscriptReplayer story) has gaps that limit its reliability as a testing foundation. This issue tracks hardening it.
Current state
Recording lives in packages/js/widget.tsx (setupTranscriptRecording()). Replay lives in PinnedRowsTranscriptReplayer.stories.tsx.
What's captured:
| Captured | Event | Content |
|---|---|---|
| Yes | custom_msg |
message type, key, buffers_len (count only) |
| Yes | infinite_resp_parsed |
key, parsed parquet rows as JSON, row/total counts |
| Yes | all_stats_update |
summary stats from df_data_dict change |
What's NOT captured:
| Missing | Event | Impact |
|---|---|---|
| Trait syncs | df_display_args, buckaroo_state, column_config |
Rendering config changes not recorded |
| JS→Python requests | infinite_request (scroll-triggered data fetches) |
Can't verify correct data ranges requested |
| Ghost events | dfi_cols_fields, dfi_grid_ready, dfi_first_data_rendered, dfi_pinned_*, ds_request, ds_success, user_operation |
Defined in TS type but never pushed — misleading |
The five gaps
1. Missing trait sync events
Only change:df_data_dict is listened to. df_display_args (column config, displayers, formatting), buckaroo_state (widget mode, active tab), and column_config (per-column styling) are not recorded. If these change during a session, replay can't reproduce the state.
2. Missing request side (JS→Python)
model.send({ type: 'infinite_request', payload_args }) in BuckarooWidgetInfinite.tsx:58 is never captured. Transcripts have responses without requests. A bug where the widget requests wrong scroll offsets wouldn't be caught.
3. Ghost event types
Six event types are defined in the TranscriptEvent union type but never actually pushed to the transcript array. Either wire them up or remove them from the type.
4. Replay path differs from real path
The replayer sets React state directly (setCfg(), setSummary(), setRawRows()). The real widget receives data through the model/comm channel → DFViewerInfinite datasource → AG-Grid getRows(). A rendering bug in the real datasource path wouldn't be caught by replay.
5. No schema version
Transcripts have no version field. Format changes silently produce wrong replays with no error signal.
Proposed hardening (tiered)
Tier 1 — Low effort, high value
- Schema version — add
schema_version: 1to every event. Replayer checks on load, throws on mismatch. - Record trait syncs — add
model.on("change:df_display_args", ...),change:buckaroo_state,change:column_configlisteners insetupTranscriptRecording(). - Clean up ghost events — either implement the
dfi_*/ds_*/user_operationrecording or remove them from the type.
Tier 2 — Medium effort
- Capture JS→Python requests — wrap
model.send()to record outgoing messages asoutgoing_requestevents. - Replay through real data path — replay should feed data through the model/comm path, not set React state directly, so the datasource → AG-Grid pipeline is exercised.
Tier 3 — Design needed
- Transcript completeness assertion — validate that a recorded transcript contains minimum expected events before trusting it.
- Round-trip validation — record a live transcript, replay it, record the replay output, compare. Catches replay path divergence.