A run is one measurement made by an experiment module — a folder of journal, plan, records and analysis files on disk. That folder is complete, but it is not something you can send a colleague. Since this month, plesty-bench (the program that manages a lab PC and runs experiments on it) compiles every finished run into a single report.html: what was run, how it was configured, which instruments took part, what the analyzers found, and every recorded value.

experiment
Run folderjournal, plan, records, analysis/
analyzer
*.report.jsonwhat each analyzer says it found
plesty-bench
Run reportreads the folder, lays it out
output
report.htmlone file, no script, nothing fetched

What a report contains

The report reads only what is already in the run folder — it invents nothing. Sections appear when the run has something to put in them:

  1. Run info — experiment, run id, final state, start and end time, steps done and failed, records committed.
  2. Bench info — the experiment module and the instruments, as the run recorded them.
  3. Device setup — for each device: which lab PC ran it, the network address the run reached it on, and where that PC sees the shared data disk. A run that was stopped and resumed lists every start.
  4. Configuration — the settings frozen into the run's plan when it started, so it is what the run actually used.
  5. Operator notes — remarks recorded during the run (“helium top-up”), placed between the steps they happened between.
  6. Analysis — each analyzer's own summary: sentences, tables and figures, with the analyzer's name, version and options.
  7. Raw data — every committed record, one table per kind of step (up to 500 rows each). A value that is the same in every row is stated once above the table instead of repeated.
Built to last. The file has its stylesheet inlined, contains no JavaScript and loads nothing from the network, so it opens from an e-mail attachment, a USB stick, or an archive years from now. Figures are inline SVG and equations are MathML. A Light / Dark switch in the header overrides the reader's system setting — done in pure CSS.

Using it

For users

You get a report without doing anything

When a run ends — completed, stopped or aborted — its job writes report.html into the run folder. A folder handed on months later explains itself. If the report cannot be compiled, that is one line in the job log; the run is not marked failed, because the measurement and its data are already safe on disk.

In the console

On the Experiments tab, select a run and open its Report pane:

ControlWhat it does
Report lineNames the run's report.html, when it was written and its size — or says when it will have one.
Export HTMLWrites a fresh copy of the report wherever you choose, with a file name that says which experiment and run it describes.
Add reportAsks What happened? and records your note in the run's journal while the run is going. Notes show up in the report's Operator notes section. Also under Experiment ▸ Report….
Open runOpens the run folder in your file manager — available while the run is going too, so you can watch files appear.
Runs measured elsewhere work too. Use Load on the Experiments tab to show a run folder from another PC, then Export HTML. The report reads the run's files directly rather than through plesty-lib's document loaders, so a bench with an older plesty-lib can still report on a run written by a newer one.

Contributing to it

For developers & contributors

1 · Make your analyzer say what it found

The Analysis section is filled from reports, a new part of plesty-lib (plesty.lib.report). A report is an ordered list of blocks — text, tables and figures — saved as a <name>.report.json file next to the analyzer's outputs. Any reader, including the bench, renders it to HTML or LaTeX without importing your analyzer.

You get a report for free: Analyzer.report(outputs) tabulates every output whose output_schema entry has "role": "result" (the default). Mark helper outputs "role": "intermediate" to keep them out, and give entries a "title". To say more, override it:

from plesty.lib.report import Cell, Figure, Report, Table, Value
from plesty.lib.monitor import Line, Scatter

def report(self, outputs):
    return Report(
        [
            r"Two of four lines split by $\Delta E = 11.5 \pm 0.3$ µeV.",
            Table(header=[[Cell("Line"), Cell(r"$\Delta E$ (µeV)")]],
                  rows=[[Cell("775.012 nm"), Value(11.5, err=0.3)]]),
            Figure([Scatter(x=angles, y=centres), Line(x=angles, y=fitted)]),
        ],
        title="Fine structure",
        provenance=self.provenance(),
    )

Cells accept **bold**, *italic*, `code` and $math$; Value(x, err=σ) is printed to the precision its uncertainty allows; rowspan= / colspan= build paper-style headers. Equations become MathML when plesty-lib is installed with its report extra.

2 · Save the report from your experiment

The experiment module decides where results live. Save the report under the run's analysis/ folder with the shared suffix, and the bench picks it up — its tables and figures replace the generic array dump it would otherwise show for those outputs:

from plesty.lib.report import REPORT_SUFFIX

stem = self.run_dir / "analysis" / subject
provenance = {"run": self.run_id, "qd": subject, "analyzer": analyzer.provenance()}
save_result(outputs["fine_structure"], f"{stem}_fine_structure", provenance)

report = analyzer.report(outputs)
report.title = f"Fine structure of {subject}"
report.provenance = provenance          # same provenance as the outputs it covers
report.save(f"{stem}{REPORT_SUFFIX}")   # → analysis/<subject>.report.json

This is exactly what the plesty-pol-pl experiment does with the plesty-fss fine-structure analyzer. Give the report the same provenance as the outputs it describes — that is how the bench knows not to list those outputs twice.

Other things the report reads, and where they come from. Operator notes are the journal's report events (plesty.lib.experiment.control.report(run_dir, "…")); the device setup comes from what plesty-lib records when a run starts. A run written by an older plesty-lib that did not record the setup simply says so in that section.

3 · Change how the report looks

Layout and style are assets, not Python strings: the markup is plesty/server/assets/report.html (named <template data-fragment> pieces with placeholders) and the style is plesty/server/assets/report.css, whose colours resolve through plesty-lib's palette tokens and CSS light-dark(). The compiler is plesty/server/services/run_report.py (report(), write(), suggested_name()); run values are always HTML-escaped. Cover a change in tests/test_run_report.py — and keep the rule that the page carries no script and fetches nothing.