Skip to content

Add a recovery trace viewer, published with the docs - #8496

Open
Amaury Chamayou (achamayou) wants to merge 6 commits into
mainfrom
achamayou-fantastic-waddle
Open

Amaury Chamayou (achamayou) wants to merge 6 commits into
mainfrom
achamayou-fantastic-waddle

Conversation

@achamayou

@achamayou Amaury Chamayou (achamayou) commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Motivation

When a trace fails to replay (#8282), the replayer names the log line and rule, but not the model state around it. This adds a viewer that steps through a whole run: the trace records, the model state after each step and what it changed, which send each receive took, and where and why the replay stopped. It is published with the docs, showing the recorded traces and some of the invalid traces stored with them.

Implementation summary

  • disaster-recovery-replay --dump FILE (DisasterRecovery/TraceValidation/Dump.lean) writes a run as JSON: its records, the reduced instructions, and the model state after each step with the actions it enables. A failing step adds each field's observed and model values, or the guards of a disabled action. It steps with runInstruction, the step that replay runs, and takes its outcome from replay, so the dump shows exactly what the replayer concludes.
  • replayer/viewer/ is a static page, vanilla JS and SVG with no dependencies, that only renders dumps: every semantic fact comes from the Lean side. build.py dumps the recorded traces, one stored invalid trace for each way a replay can stop, applied as check-fixtures.sh applies it, and any --logs DIR of node logs.
  • doc/operations/recovery.rst says how to view your own traces. doc/conf.py builds the viewer into the site as trace-viewer/, like doxygen (SKIP_TRACE_VIEWER skips it), and doc.yml installs Lean for that, with the same pinned elan installer as the SNP job. The docs ctest that PR CI runs sets SKIP_TRACE_VIEWER, as its runner has no Lean.
  • The Lean workflow runs build.py, which fails if a dump is missing or its outcome disagrees with the replayer's exit code. The quorum and multiple-timeout fixtures gain an invalid trace, commit-order.retry_after_end, the first that stops at a disabled action.

To review: on the Lean side there is Dump.lean, a --dump flag in replayer/Main.lean and a runInstruction hook in TraceValidation.lean. Dump.lean calls the replayer and the model rather than repeating them. viewer.js and index.html are presentation only.

Safety and compatibility

No runtime impact: this changes no CCF code and does not change the model. The published viewer shows only checked-in test fixtures. The docs workflow does not run on pull requests, so its sphinx-multiversion command was run locally from this branch, for this branch and main. This branch's site has trace-viewer/ with every dump. main has no viewer, and its site builds without one, as older release branches will.

@achamayou
Amaury Chamayou (achamayou) requested a review from a team as a code owner October 2, 2026 14:32
@achamayou
Amaury Chamayou (achamayou) added this pull request to stack #8367 October 2, 2026 14:34
Copilot AI balanced review requested due to automatic review settings October 2, 2026 14:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Run-ID collisions, broken first-step links, misleading preflight failures, and inaccessible controls affect core viewer behavior.

Review effort: Balanced
Findings: 4 Medium severity · 1 Low severity

Open (5)
What changed in this PR

Adds a documentation-published recovery trace viewer without changing CCF runtime behavior.

Changes:

  • Adds Lean JSON replay dumps and diagnostics.
  • Adds a static trace viewer and mutant fixture generation.
  • Integrates viewer generation into documentation and CI workflows.

Custom instructions used

  • .github/copilot-instructions.md
  • .github/instructions/changelog.instructions.md
  • .github/skills/testing/SKILL.md
  • .github/skills/formatting-and-linting/SKILL.md
File Description
tests/​infra/​recovery_trace_mutations.py Adds the disabled-retry mutant.
lean/​disaster-recovery/​replay/​viewer/​viewer.js Implements trace visualization and interaction.
lean/​disaster-recovery/​replay/​viewer/​index.html Defines the viewer UI and styling.
lean/​disaster-recovery/​replay/​viewer/​build.py Generates fixture and mutant dumps.
lean/​disaster-recovery/​replay/​viewer/​.gitignore Excludes generated viewer data.
lean/​disaster-recovery/​replay/​ReplayMain.lean Adds the --dump option.
lean/​disaster-recovery/​replay/​README.md Documents dump generation and viewing.
lean/​disaster-recovery/​DisasterRecovery/​Replay/​Dump.lean Serializes replay states and diagnostics.
lean/​disaster-recovery/​DisasterRecovery/​Replay.lean Exposes single-instruction replay.
lean/​disaster-recovery/​DisasterRecovery.lean Exports the dump module.
doc/​operations/​recovery.rst Documents trace collection and viewing.
doc/​contribute/​build_ccf.rst Documents viewer build requirements.
doc/​conf.py Builds and publishes the viewer.
CMakeLists.txt Skips viewer generation in docs tests.
.github/​workflows/​lean.yml Validates viewer dump generation.
.github/​workflows/​doc.yml Installs Lean for documentation builds.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lean/disaster-recovery/replay/viewer/build.py
Comment thread lean/disaster-recovery/replayer/viewer/index.html
Comment thread lean/disaster-recovery/replay/viewer/viewer.js Outdated
Comment thread lean/disaster-recovery/replayer/viewer/viewer.js
Comment thread lean/disaster-recovery/replay/viewer/viewer.js Outdated
Comment thread lean/disaster-recovery/replay/viewer/build.py Outdated
@achamayou
Amaury Chamayou (achamayou) force-pushed the achamayou-fantastic-waddle branch 2 times, most recently from 97b44d2 to 4f3ce4b Compare October 6, 2026 15:20
@achamayou
Amaury Chamayou (achamayou) force-pushed the achamayou-fantastic-waddle branch 4 times, most recently from ef98ac9 to ad2e1cb Compare October 7, 2026 10:14
@achamayou
Amaury Chamayou (achamayou) force-pushed the achamayou-fantastic-waddle branch 8 times, most recently from 69ec00a to 5bdc891 Compare October 9, 2026 14:36
Base automatically changed from achamayou-fluffy-parakeet to main October 9, 2026 14:58
@achamayou
Amaury Chamayou (achamayou) force-pushed the achamayou-fantastic-waddle branch 2 times, most recently from d79b071 to 7e21e6f Compare October 9, 2026 16:59
disaster-recovery-replay --dump FILE writes a run as JSON: its records, the
reduced instructions, and the model state after each step with the actions it
enables. It also holds the queued copy that each delivery took, and each
check's result, with each field's observed and model values when one fails.
It replays through the same runInstruction and replay as the check, so the
dump shows exactly what the replayer concludes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
replayer/viewer/ is a static page that steps through a run written by
disaster-recovery-replay --dump. It shows the trace records beside the model
state of every node and the network, what changed at each step, which send
each receive took, and where and why a replay stopped. It only renders dumps:
every semantic fact comes from the replayer.

build.py dumps the recorded traces in the replay fixtures, one stored invalid
trace for each way a replay can stop, which it applies as check-fixtures.sh
does, and any --logs DIR of node logs into viewer/data/. The quorum and
multiple-timeout fixtures gain an invalid trace, commit-order.retry_after_end,
the first that stops at a disabled action.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The recovery documentation says how to view your own traces. Like doxygen,
doc/conf.py builds the replayer and the viewer's runs into the site as
trace-viewer/ unless SKIP_TRACE_VIEWER is set, and skips older trees without
a viewer. doc.yml installs Lean for that with the SNP job's pinned elan
installer. The docs ctest sets SKIP_TRACE_VIEWER, as its runner has no Lean.
The Lean workflow runs build.py, which fails if a dump is missing or its
outcome disagrees with the replayer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A run's id names its dump in data/, so a --logs directory named like a
fixture, another --logs directory or a stored trace silently replaced that
run's dump, and index.json listed the id twice. build.py now exits naming the
id before it writes the second dump. It also rejects the id index, whose dump
index.json would replace.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The replayer rejects a configuration that the model does not accept, such
as one with duplicate expected locations, before it runs any step, and the
dump then marks every step skipped. The viewer said that the replay failed
at step 0, and linked a step 0 that does not exist. It now says that the
replay stopped before step 1, with the replayer's message, and that the
skipped steps show the initial state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The node and kind filters, the replay and log order tabs, and the step and
record links were click-only spans and links without an href, and the open
dump label wrapped a hidden file input, so none of them could take focus.
They are now buttons, with aria-pressed on the filters and tabs, and the
file input is out of sight but focusable, with a focus ring on its label.
They look as before: the underlines stay on the text, as on inline links.

Chrome also moved the point that Tab starts from to each row that the
viewer scrolled into view, so after the page loaded, Tab skipped the
controls above the state pane. The rows pane now scrolls itself, to the
same offsets as scrollIntoView.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
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.

4 participants