Add timeline report: render folded execution as self-contained HTML - #16
Merged
Conversation
The last v0.2 item. The log already contains everything an execution did, so a timeline is a fold, not an instrumentation layer — this renders that fold. Shaped after the OTel exporter rather than as a live view: it consumes an ExecutionState (itself only a fold of the log) and installs no runtime hook, so an execution recorded months ago renders exactly as well as a fresh one, and the log stays the single source of truth. Two consequences are gated in CI because they are what make a report worth having: - Self-contained. Inline CSS, no scripts, fonts or images, so a report opens from file:// with nothing else present and can be attached to a ticket. - Deterministic. Being a pure function of the fold, two renders of one execution are byte-identical, which is what lets a report be diffed or committed as a build artifact. Everything interpolated is HTML-escaped. Tool names, effect labels and recorded payloads are log content, and a report is likely to be opened in a browser by someone other than whoever produced the execution. Oversized payloads are elided rather than inlined so one large completion cannot swamp the page. The module depends on catalyst-core alone — no templating engine, no web server. Deliberately left out for now: latency bars and a TrajectoryDiff view. The table is the read-only view the roadmap asked for; visual timing and diff rendering are polish on top of it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G54yVgLZGZ3mzBv4kPc9F3
Greptile SummaryAdds a self-contained HTML timeline report for folded execution state.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported Unicode truncation defect is corrected by backing up cuts that split surrogate pairs and is covered by focused boundary tests. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Execution event log] --> B[ExecutionState fold]
B --> C[TimelineReport.html]
C --> D[Self-contained HTML document]
C --> E[TimelineReport.writeTo]
E --> F[Portable report file]
Reviews (3): Last reviewed commit: "CI: restore the streaming step's run blo..." | Re-trigger Greptile |
…eview) Truncating a serialized payload at a raw UTF-16 index can cut between the halves of a surrogate pair. The lone surrogate left behind is unmappable in UTF-8, so it reaches the page as a replacement character — a visibly corrupted last character in what is meant to be a faithful record. Emoji turn up in completions routinely, so the boundary is worth respecting. The test sweeps padding lengths around the cut rather than guessing which one straddles it: the payload is wrapped in a JSON envelope before truncation, so the offset that lands mid-pair is not predictable from the payload alone. My first attempt fixed the position analytically and passed against the unfixed code — the sweep fails at pad=1951 without the fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G54yVgLZGZ3mzBv4kPc9F3
contrasam
force-pushed
the
claude/timeline-html
branch
from
July 25, 2026 07:31
c5c735f to
0685de1
Compare
The rebase onto main put the streaming and timeline steps' conflict boundary mid-step, and resolving it left the streaming step with a name and no run:, with both scripts concatenated under the timeline step. A step with neither run: nor uses: is invalid, so the workflow failed to start — the run finished in the same second it was created, with the workflow shown by path rather than by name, and no build check ever appeared on the PR. The YAML parsed fine, which is why the check I ran after the rebase missed it: it verified structure and unknown keys but never asserted the one thing that mattered, that every step actually has something to execute. Confirmed the repaired file by running both restored steps verbatim from the parsed workflow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G54yVgLZGZ3mzBv4kPc9F3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the v0.2 timeline UI exit criterion (spec §12): a new
catalyst-timelinemodule that renders an execution's folded state as a read-only, self-contained HTML report. The report displays execution status, token/cost roll-ups fromtimelineView(), and a step-by-step trajectory table with latencies and recorded payloads.Key Changes
New module
catalyst-timelinewithTimelineReportclass:TimelineReport.html(ExecutionState)— renders a complete HTML document with inline styles, no external referencesTimelineReport.writeTo(ExecutionState, Path)— writes the report to a file, creating parent directories as neededDesign constraints enforced:
ExecutionState, installs no runtime hook; the log remains the only source of truthfile://URLscatalyst-core: no templating engine, no web server, no Jackson beyond what core already usesReport structure:
Comprehensive test coverage:
TimelineReportTest: unit tests for HTML generation, escaping, determinism, payload elision, file writingTimelineAcceptanceTest: end-to-end test rendering a mixed execution (model calls, tool calls, effects, memory writes) and verifying self-containment and determinismIntegration:
Democlass withtimelinesubcommand demonstrating the full workflowImplementation Details
&,<,>,",') applied uniformly to all interpolated values<details>elements for collapsible display, with character count and elision indicatorhttps://claude.ai/code/session_01G54yVgLZGZ3mzBv4kPc9F3