Appearance
Reports
scripts/dashboard/reports.js builds one bob-reports/1 document: every report the fleet produced in the last 14 days, newest first (#2073). Reports are a view, not a scroll through GitHub. Nothing is stored. Every build reads each source again.
Commands
bash
node scripts/dashboard/reports.js # one block per report, then each source's status
node scripts/dashboard/reports.js --json # the bob-reports/1 documentDocument
json
{
"schema": "bob-reports/1",
"generated_at": "2026-09-13T22:00:00.000Z",
"refresh_s": null,
"machine": "macbook-air",
"window_days": 14,
"since": "2026-08-30T22:00:00.000Z",
"sources": {
"tick-digest": {
"status": "ok", "reason": null, "count": 1,
"machines": [
{ "id": "macbook-air", "source": "local", "as_of": "2026-09-13T22:00:00.000Z", "stale": false, "count": 0, "reason": null },
{ "id": "farm-01", "source": "snapshot", "as_of": "2026-09-13T21:30:00Z", "stale": false, "count": 1, "reason": null }
]
},
"session-report": { "status": "unavailable", "reason": "rate-limited" },
"status-report": { "status": "ok", "reason": null, "count": 0, "truncated": false }
},
"reports": [
{
"kind": "tick-digest", "title": "bob tick 2026-09-13", "at": "2026-09-13T03:12:00Z",
"project": "bigbrain", "machine": "farm-01",
"ref": "paulirv/bigbrain#2311", "url": "https://github.com/paulirv/bigbrain/issues/2311",
"verdict": "ok — 2 merged", "exit": 0,
"markdown": "## bob tick — 2026-09-13 (live) on farm-01\n…", "stale": false
}
]
}Report keys
| Key | Meaning |
|---|---|
kind | tick-digest, session-report or status-report. |
title | The issue title. For a digest, bob tick <date>, with the mode in brackets when it was not live. |
at | When the report was made: a digest's finished_at (else started_at, else its date), an issue's createdAt. |
project | The projects.json name. A digest's project is matched by its directory, then by basename (a remote machine's path does not resolve here), else it is the basename. |
machine | The machine a digest ran on. null for issues, which live on the forge. |
ref, url | owner/repo#N and its link. A digest links the plan issue the tick ran, which carries the digest comment. Both are null for a digest with no plan; url is null when the plan's repo is unknown. |
verdict, exit | A digest's verdict line and exit code. null for issues. |
markdown | A digest's rendered .md, as bob tick wrote it. null for issues, and for a digest whose .md is missing. |
stale | true for a digest read from a snapshot older than BOB_FLEET_STALE_SECONDS (default 24 h). |
state | An issue's open or closed. Issues only. |
Reports are ordered newest at first. Anything older than since (generated_at minus window_days) is left out.
Sources
| Source | Read from |
|---|---|
tick-digest | This machine: every tick-digest/1 in $BOB_HOME/fleet/ticks/ in the window, with its .md. Every other registry machine: its newest snapshot's last_tick (Fleet Snapshot Timer), since bob tick writes a digest only where it ran (#2054). A remote machine therefore contributes its newest digest, and a new one within one snapshot interval. |
session-report | gh search issues --label session-report --created >=<since> over the registry's owners, newest first, filtered to repos a projects.json entry on this machine has as its origin. |
status-report | The same search for status-report. An issue carrying both labels is listed once, as a session-report. |
Every source reports a status:
status | Meaning |
|---|---|
ok | Read. count is how many reports it produced. truncated: true means a search returned a full page of 100, so older reports may be missing. |
unavailable | The read failed. reason is typed: for gh, the #1968 names (gh-missing, unauthenticated, rate-limited, and, from the dashboard server, server-cannot-run-gh and gh-failing), else unavailable. The digests still list. |
not-measured | There is nothing to read: no project on this machine has a GitHub origin. |
tick-digest.machines says, per machine, where its digests came from: local, snapshot (with as_of and stale), or null with a reason. A machine that published no snapshot, or whose snapshot predates last_tick, is named there, so a missing digest is never mistaken for a machine that ran no tick.
Reads
- gh goes through the shim. Both searches run on
PATH, where the gh shim cachessearch issuesreads (the forge cache, #1749). When the forge is down, a recent cached read is served instead of a failure. - Two searches. A build costs two search API calls.
- Local reads for digests. This machine's tick directory and the snapshot directory. No network call.
Served by the dashboard
bob dash serve (the one dashboard server, scripts/dashboard/server.js) serves the document at /reports.json. bob viz renders it as the Reports pane on /bob.
| Behaviour | Detail |
|---|---|
| Refresh | Rebuilt at most once every refresh_s seconds (DASH_REPORTS_REFRESH_S, default 120), however many tabs poll it: a build runs two issue searches. A request that arrives during a build waits for that build instead of starting another. A digest published in a snapshot is on the page within one snapshot interval plus one rebuild and one poll. |
| Page | /bob re-reads /reports.json every refresh_s and repaints only when the pane changed, so a digest folded or opened by hand stays that way. Each entry shows its kind, machine and project, its date, and its title linked to its issue. A tick digest also shows its verdict and its markdown; the newest digest is open and the rest fold. |
| gh | The issue searches use the server's own gh runner, so they count toward its gh liveness tracker (#1968). An unreadable session-report or status-report carries the server's reason, which can also be server-cannot-run-gh or gh-failing, and the document gains the same gh evidence block as the /warp panes. The pane prints each reason with what to do about it, and still lists the digests. |
| Render | scripts/dashboard/bob-reports.js, served as /bob/reports.js, is a pure function of the document. It renders the markdown bob tick writes (headings, bold, code spans, pipe tables, - lists) from escaped text, so nothing inside a digest can inject markup. tests/test-reports-pane.js snapshots its output (tests/fixtures/bob-viz/reports.html). |
| Failure | If the document cannot be built at all, the response has reports: [] and an error, and the pane shows the error. "no reports in the last 14 days" appears only when every source was read. |
See also
- Notices: the
bob-notices/1inbox built the same way - Fleet Snapshot Timer:
last_tick, and what keeps it fresh - bob viz: the page these reports are for
tests/test-reports-pane.js: ordering, the 14-day window, gh unavailable