Project Detail
Project Detail
Section titled “Project Detail”scripts/dashboard/project-detail.js builds one bob-project-detail/1
document for one project on one machine (#2924). It holds what an expanded
bob viz card shows beyond the compact tile. The
fleet feed is pushed to every open page, so it carries only
what a tile needs. This document is fetched when a card is opened.
Commands
Section titled “Commands”node scripts/dashboard/project-detail.js <machine> <project> # the bob-project-detail/1 document; exit 3 + {"error"} when unknownGET /bob/project/<machine>/<name>.json → 200 bob-project-detail/1 → 404 {"error": "no machine …" | "no project … on …"} → 500 {"error": "project detail failed: …"}The dashboard server serves it next to
/fleet.json. A card fetches it when it is opened, and
scripts/dashboard/bob-card.js renders it
(Expanded card, #2925). While the
card stays open, the page re-reads it every refresh_s. It is never pushed.
- Cached per project. A document is rebuilt at most once per
DASH_DETAIL_REFRESH_S(default 120 s), however many tabs open the card. Concurrent requests for a project that is building wait for that build and share its gh reads. - Bounded. One build makes up to seven gh reads: three labelled issue
lists, PRs, the last run, and the run’s issue and flight plan when a run
names them. Cost and reports come from the server’s cached
/series.jsonand/reports.jsonbuilds, so they add no gh reads. - Degraded forge. When a build’s forge reads fail, the server serves the
last good document instead. That document carries
forge: {status: "degraded", reason, fix, failed, cached_age_s}and the #1968ghevidence block, as/notices.jsondoes. The next build that succeeds drops the label. When there is no earlier good document, the new build is served with the failed partsunavailableandcached_age_s: null. - Unknown targets are a 404 with a JSON error object: a machine the registry does not declare, a project the feed has no row for on that machine, or a malformed path. A failed build is a 500 with an error object. Neither ever returns a stack trace.
Where each section comes from
Section titled “Where each section comes from”| Section | Project on this machine | Project on another machine |
|---|---|---|
session |
the warp state file, read live | the snapshot’s warp run record |
activity.commits |
git log -5 |
the snapshot’s last_commit only (commits_complete: false) |
activity.prs |
gh pr list |
gh pr list |
queue |
gh issue list per label, plus the flight plan issue |
the same |
health |
.project-ready.json (with each failing check’s fix), the harness-defect and advisory state files, and the declared CI locus. gh run list supplies the last CI run. |
the snapshot’s project_ready (check names only), harness_defects, advisories and ci. gh run list supplies the last CI run. |
cost |
this server’s bob-series/1 row for the project |
the same, when the project is registered here |
reports |
this server’s bob-reports/1 and the latest stored briefing |
the same |
links |
the repo URL; dev.json (url or server.port, then environments.prod.url); docs-site.json base_url; the /bob/links.json entry |
the same. There is no dev URL, because a localhost URL on another machine does not reach it. |
A project on another machine is never contacted. Its facts are whatever its
last snapshot published, and the document’s machine.age_s and
machine.stale say how old that is. The forge-derived parts are read by the
serving machine, because the repo is the same wherever it is checked out. The
repo is the local registration’s origin, else the snapshot’s ci.slug.
The run context (issue, chunk, branch, host_session, flightplan) is
read by scripts/fleet/project-live.js, so audit.js snapshot publishes it
too. A snapshot published before #2924 lacks it. Each of those fields then
reads not measured with that reason.
session.attach is set while a run is active (#3163). command is the one
attach command, bob warp attach <project>, which follows the run to each new
segment, so there is no warp-seg-<N> to look up. machine names the machine
to run it on, and here is false when that is not the serving machine. The
card shows it as the attach row of Now. It is null when no run is
active.
Document
Section titled “Document”{ "schema": "bob-project-detail/1", "generated_at": "2026-09-23T03:00:00.000Z", "refresh_s": 120, "machine": { "id": "farm-01", "label": "The Farm (worker 01)", "current": true, "source": "live", "as_of": "…", "age_s": 0, "stale": false }, "project": { "name": "bigbrain", "repo": "paulirv/bigbrain" }, "forge": { "status": "ok", "reason": null, "fix": null, "failed": [], "cached_age_s": null }, "session": { "status": "ok", "reason": null, "session": "active", "phase": "coding", "issue": { "number": 2924, "title": "bob-project-detail/1: …", "url": "https://github.com/paulirv/bigbrain/issues/2924" }, "chunk": { "index": 0, "total": 2 }, "elapsed_s": 7884, "tokens": 757127, "branch": "feature/issue-2924-project-detail", "host_session": { "kind": "tmux", "name": "warp-seg-bigbrain-6", "window": "warp-seg-6" }, "attach": { "command": "bob warp attach bigbrain", "machine": "farm-01", "here": true }, "flightplan": { "number": 2921, "url": "…/issues/2921", "done": 7, "total": 13 }, "not_measured": {} }, "activity": { "status": "ok", "reason": null, "commits": [{ "sha": "…", "subject": "…", "at": "…", "age_s": 120, "url": "…/commit/…" }], "commits_complete": true, "prs": [{ "number": 2957, "title": "…", "draft": false, "ci": "success", "url": "…" }], "not_measured": {} }, "queue": { "status": "ok", "reason": null, "approved": 111, "next": { "number": 2924, "title": "…", "url": "…" }, "next_from": "flightplan", "open_bugs": 16, "open_p1": 13, "not_measured": {} }, "health": { "status": "ok", "reason": null, "project_ready": { "verdict": "READY", "ok": true, "at": "…", "failing": [] }, "preflight": null, "ci": { "locus": "farm", "label": "self-hosted-bob", "verdict": "unmeasured", "drift": null, "fix": null, "queue": null, "last_run": { "conclusion": null, "status": "in_progress", "workflow": "CI", "branch": "master", "at": "…", "url": "…" } }, "harness_defects": { "open": 0, "recurrences": 0, "unreported": 0, "fingerprints": [], "issues": [] }, "advisories": null, "not_measured": { "advisories": "no dependency audit has run on farm-01" } }, "cost": { "status": "ok", "reason": null, "window": { "days": 30 }, "as_of": "…", "machine": "farm-01", "series": { "usd_per_day": { "status": "ok" } }, "not_measured": {} }, "reports": { "status": "ok", "reason": null, "session_report": { "title": "…", "url": "…" }, "tick_digest": null, "brief": { "file": "…", "items": 2, "url": "/briefings" }, "not_measured": { "tick_digest": "…" } }, "links": { "status": "ok", "reason": null, "repo": "https://github.com/paulirv/bigbrain", "approved": "…", "prs": "…/pulls", "actions": "…/actions", "warp_viz": { "path": "/warp", "url": null, "port": null }, "dev": null, "deploy": null, "docs": null, "not_measured": { "dev": "no dev URL (dev.json) declared" } }}forgesays whether the gh reads landed. It isok,degraded(the first failed read’s typed reason, itsfix, and which reads failed) ornot-measured(no GitHub repo known). The gh reason names are the ones Notices uses. Each has one fix:gh-missing→ install gh,rate-limited→ wait for the window,unauthenticated→gh auth login,server-cannot-run-gh→bob warp viz(restart from a fresh shell), anything else →bob forge health.- Every section has a
status. It isok,not-measuredorunavailable, with areasonwhen it is notok. When a section is readable but one field is not, the field isnullandnot_measured[field]says why. - Nothing is defaulted. A queue that could not be read is
unavailable, neverapproved: 0. An unaudited project hasadvisories: null, never zero open advisories. A PR with no checks hasci: null, never a pass. An in-progress run hasconclusion: null. - Elapsed is as of the source. On a snapshot,
session.elapsed_sis measured to the snapshot’sgenerated_at, as the feed measures it. - The queue counts are exact. Each count comes from its own labelled list
(
approved,bug,p1-critical), up to 200 each. A count that reaches the limit is a lower bound, and itsnot_measuredentry says so. - The next item is the first unticked item of the run’s flight plan
(
next_from: "flightplan"). Without a plan, it is the approved queue’s head in the warp-drive order: priority, then bugs before reqs, then oldest first (next_from: "approved"). - The warp viz link is the
/bob/links.jsonentry for the project, which ismonitorLinksinscripts/dashboard/fleet-links.js. No URL is built here.
Related
Section titled “Related”- Fleet Feed: the compact tile’s data.
- Notices: the gh reason names and fixes this document reuses.
- Cost and Churn Series and Reports: the documents
costandreportsare drawn from.