Skip to content

feat(trace): event model with run-level format version and tolerant read path - #2872

Merged
esokullu merged 1 commit into
webbrain-one:mainfrom
alectimison-maker:feat/trace-event-model
Aug 21, 2026
Merged

feat(trace): event model with run-level format version and tolerant read path#2872
esokullu merged 1 commit into
webbrain-one:mainfrom
alectimison-maker:feat/trace-event-model

Conversation

@alectimison-maker

Copy link
Copy Markdown
Contributor

Summary

  • New pure module trace/event-model.js (Chrome + Firefox): authoritative EVENT_KINDS catalog, TRACE_FORMAT_VERSION, and makeEvent() envelope construction with write-side validation.
  • The recorder routes every event write through the model and stamps traceFormatVersion: 1 on new run records.
  • Tolerant read path: the Traces UI renders unknown kinds as an explicit "Unknown event" placeholder (and collapses ignorable kinds); the Markdown exporter skips unknown kinds and reports a count in the footer.

Motivation

Closes #2869.

WebBrain's trace events were free-form {runId, seq, ts, kind, data} with three internal problems:

  1. No kind catalog — event types were added incrementally over time but no single place defined the full set of valid kinds; a typo'd kind silently disappeared from the UI.
  2. No format version — neither events nor runs carried a version, so the next required-field addition would make old traces unreadable with nothing to negotiate against. The project already handles legacy trace data ad-hoc (Traces UI tolerates conversationId: null runs, trace-export.js has legacy branches).
  3. No defined read-side policy — UI and exporters had undefined behavior for unknown kinds: silent blank rendering, silently dropped data without counting.

Design

  • EVENT_KINDS covers all 9 existing kinds and is consulted by the recorder, the Traces UI, and the exporter, so a new event type has one declared home instead of per-reader lists.
  • IGNORABLE_KINDS starts empty; the mechanism is in place so a future "safe to collapse" event type has a defined place. The UI honors the flag; nothing is ignorable today.
  • makeEvent() returns null (never throws) for unknown kinds or data that cannot survive a JSON round-trip (circular, BigInt). The recorder skips a null envelope with a warning — a recording bug surfaces at write time and can never break a run. The screenshot timeline marker now goes through the same envelope path.
  • Run records gain traceFormatVersion: 1; older runs without the field (= version 0) are untouched.
  • Read side is deliberately tolerant rather than fail-closed: WebBrain has no log-rebuild semantics and must keep displaying existing traces. Unknown events are kept visible (explicit placeholder), never silently dropped, and exporters count them.
  • validateEventLog() provides read-side tooling (seq contiguity + unknown-kind detection) for tests and future consumers.
  • All new fields are content-free (version integer, kind names) — the privacy contract is unchanged.

Testing

  • node test/run.js — passed, 1959 tests (7 new: catalog coverage vs recorder usage, envelope validation, log validation, mirror identity + browser-neutrality, recorder wiring, exporter skip/count, UI placeholder)
  • npm run test:toolbar-guard — passed (33 tests)
  • npm run test:security — passed (60/60 checks)
  • node --check on every touched file — passed

Skipped: unpacked-browser manual verification (no browser session available in this environment); both Chrome and Firefox builds are covered by the mirror-consistency tests instead. Untested browsers: Chrome, Firefox (runtime UI rendering of the new placeholder not manually exercised).

Compatibility and risks

  • Events keep the exact stored shape; only the screenshot marker's construction changed (same output shape, now validated).
  • Old runs without traceFormatVersion remain fully readable; the version is informational today and becomes the negotiation point for future format changes.
  • Risk: an unknown kind in an older trace now renders a labeled placeholder instead of the previous generic JSON view — a strictly clearer result, and only for kinds outside the catalog.

Scope

Deliberately deferred (follow-ups, separate PRs): turn/step boundary events, session lineage fields, checkpoint/repair semantics, projections, OTLP association. This PR only establishes the event model foundation with no user-visible behavior change.

…nt read path

Introduce trace/event-model.js as the single source of truth for the
per-run event vocabulary (EVENT_KINDS), the run-level trace format
version (TRACE_FORMAT_VERSION), and write-side envelope validation
(makeEvent rejects unknown kinds and data that cannot survive a JSON
round-trip). The recorder routes every event write through the model
and stamps traceFormatVersion on new run records.

Read side becomes tolerant instead of silently losing events: the
Traces UI renders unknown kinds as an explicit placeholder (and
collapses ignorable kinds), and the Markdown exporter skips them with
a count in the footer. Old runs without the version field remain fully
readable.

Mirrored to Firefox. Closes webbrain-one#2869
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

@alectimison-maker is attempting to deploy a commit to the esokullu's projects Team on Vercel.

A member of the Team first needs to authorize it.

@esokullu
esokullu merged commit 600be75 into webbrain-one:main Aug 21, 2026
1 of 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.

trace: event model with run-level format version and tolerant read path

2 participants