The archive and the reports
One file from CI must explain the run to a reader who was not there. That file is the .prototrace: it holds the execution story, the state, the attachments and the reports the run wrote.
- Name what a .prototrace holds.
- Find the JSON and HTML reports inside an archive.
- Read a downloaded workbook and the checks it went through.
- Contract coverage, not code coverage (lesson 2).
- Nothing installed. The archives are on this site.
The scenario
Some evidence does not fit in a span. A downloaded workbook, a response body, a summary a hook attached: the run keeps those as attachments, with the bytes, so a reader two days later holds the same file the test checked.
The sheets journey is built to show that. The application writes a real OpenXML workbook, the test downloads it and asserts it through a record model, and the workbook lands in the archive.
What the archive holds
A .prototrace is a zip with named entries:
| Entry | What it is |
|---|---|
spans.json | the operations: setup, execution, teardown, every request, check and release |
state.json | what existed and changed: clients, contexts, resources and tracked values |
sources/ | the source files the recording touched, so the trace can name a line |
resources/ | the attachments and the run artifacts, including the reports |
manifest.json | the map of the entries above |
The sample configures both report sinks in one place:
1.ConfigureTracing(trace =>2{3trace.ActivitySources.Add("Northstar.Domain");4})5.AddSink<JsonReportSink>(sink => sink.OutputPath = Path.Combine(6"TestResults", "Northstar.ProtoTest", "report.json"))7.AddSink<HtmlReportSink>(sink =>8{9sink.OutputPath = Path.Combine("TestResults", "Northstar.ProtoTest", "report.html");10sink.Title = "Northstar Learning demo";11});
- The application spans
The domain activity source is captured into the trace. The trace path keeps its default TestResults/prototest-{runId}.prototrace, one archive per run, so a rerun never overwrites the last run.
- Both sinks copied into the archive
The JSON and HTML reports are written beside the trace and copied into resources/, so one upload carries all three.
samples/Northstar.ProtoTest/Setup.cs. The sink paths below TestResults/Northstar.ProtoTest/ are the local default.Both files are written at the end of the run and copied into the archive, so the one artifact a CI job uploads carries the story and the report.
The journey that proves it
SheetsJourney.TheMonthlyReportMatchesItsModel creates a project, downloads the monthly report and reads it as records:
1[Sheet("Summary", HeaderRows = [1])]2public sealed record ProjectReportRow(3[property: Column("Name", Unique = true)] string Name,4[property: Column("Status", Pattern = "^[a-z]+$")] string Status,5[property: Column("Environments", Min = 0)] int Environments);
- Describe the sheet once
The record names the sheet, the header row and the columns, and the model check reads the workbook against it.
- Rules per column
Unique, a pattern, a minimum: the model turns layout expectations into ordinary checks.
Proto.Context.Sheets(), calls report.Should.MatchModel(), checks a column and reads the row it created.From the archive:
| Entry | Reading |
|---|---|
http.request REST GET /api/v1/reports/monthly.xlsx, 128.5 ms, HTTP 200 | the download, with the response attached |
sheets.open, 28.2 ms, then sheets.model | the workbook was opened and the record model built |
assert.sheets, Summary.Environments | the column check the model recorded |
attachment.publish, <test id>-rest-01-response | the workbook's bytes, kept in the run |
How to read one
- Download the archive from a lesson, a report link or a CI artifact.
- Open it in the viewer to walk the operations and the state.
- Open the same file with an archive tool to read
resources/run/JsonReportSink/run-artifact-1/report.json, or open thereport.htmlbeside it in a browser. - Open an attachment under
resources/<test id>/to see the exact bytes the test checked.
The viewer reads the file locally in the browser. Nothing is uploaded anywhere.
Checkpoint
The test never writes the workbook to disk. Where is it after the run, and what shows that the sheet model was checked?
resources/.resources/<test id>/artifact-1/<test id>-rest-01-response, 2,010 bytes of workbook. The execution layer holds the sheets.open, sheets.model and assert.sheets entries, and the embedded report carries the sheet coverage rows the model and the column check recorded, Summary!A2:C2 and Summary!C2:C2.What you learned
- A .prototrace holds the operations, the state, the source files, the attachments and the reports.
- Response bytes live in the archive as attachments, so the evidence travels with the run.
- The viewer draws the execution story; the reports are files inside the same archive.