Skip to content

Build master @ bc50cd5bunreleased — 31 commits past v1.282.0Last reviewed Last changed Grade fresh (aging >90d, stale >180d)Source / History

Cost and Churn Series ​

scripts/dashboard/series.js builds one bob-series/1 document: where the money goes and how the work churns, for every project registered on this machine, over a 30-day window (#2072). It is data for sparklines. Every figure reconciles with a CLI that already exists: dollars come from token-report.js's model-aware rate table (#1805) through the same functions token-report.js calls, never a second price list.

Commands ​

bash
node scripts/dashboard/series.js          # one line per series per project
node scripts/dashboard/series.js --json   # the bob-series/1 document

Document ​

json
{
  "schema": "bob-series/1",
  "generated_at": "2026-09-13T22:00:00.000Z",
  "refresh_s": null,
  "machine": "farm-01",
  "window": { "days": 30, "from": "2026-08-15", "to": "2026-09-13" },
  "pricing": { "as_of": "2026-06-24", "unknown_policy": "upper-bound: …" },
  "projects": [
    {
      "name": "bigbrain",
      "repo": "paulirv/bigbrain",
      "series": {
        "tokens_per_day": {
          "status": "ok", "reason": null, "shape": "daily", "unit": "tokens",
          "source": "~/.claude/token-usage.jsonl (session records, total_tokens)",
          "as_of": "2026-09-13T22:00:00.000Z",
          "value": 15000, "runs": 3,
          "points": [{ "x": "2026-08-15", "value": 0 }, "…30 points"]
        },
        "ci_duration": {
          "status": "unavailable", "reason": "rate-limited", "shape": "events", "unit": "seconds",
          "source": "gh run list --repo paulirv/bigbrain", "as_of": "…", "value": null, "points": []
        }
      }
    }
  ]
}

Every series has the same frame:

KeyMeaning
statusok, not-measured (the source is absent or was not read), or unavailable (the source failed; gh failures use the #1968 reason names)
reasonWhy there is no data. null when status is ok
shapedaily (one point per day of the window; a day with nothing is a measured 0), weekly (7-day buckets), events (one point per run, requirement or CI run) or current (one point: the count now)
unittokens, usd, ratio, recurrences, reruns, seconds or releases
sourceWhere the figures were read
as_ofWhen they were read (the document's clock)
valueThe series' summary figure (below). null when there is nothing to summarise
points[{ x, value, … }]: x is a YYYY-MM-DD day or an ISO instant

A series whose status is not ok has value: null and no points. It renders as not measured, never as a flat line that reads as zero.

Series ​

SeriesShapevalueRead from
tokens_per_daydailytotal tokens in the window (runs: session count)~/.claude/token-usage.jsonl session records whose project names the repo (owner/repo) or the project name
usd_per_daydailytotal USD. qualified: false when any record carries no priced model (an upper bound, #1805). decision_split carries the project's decision-shaped share by backend as decision-split/1, counting only the seam calls that joined one of its sessions (token-monitoring, #2983)the same records, estimateCost
usd_per_runeventsmean USD per session. Each point's ref is the session's requirementthe same records
usd_per_merged_reqeventsmean USD per priced merged requirement. merged: issues referenced; unpriced: merged issues with no sessionthe same records, joined on each record's requirement to the #N references of default-branch commits in the window (a Merge … subject's #N is a PR and is skipped)
fix_to_featweeklyfix commits per feat commit (fix, feat counts beside it). null for a span with no feat commitconventional-commit prefixes (fix:, fix(…), fix!) on the default branch: origin's HEAD, else main, else master, else HEAD
harness_defect_recurrencescurrentrecurrences recorded now (open, unreported beside it)the project's warp-drive state file, through harness-defect-summary.js stateSummary, the reader audit.js snapshot uses for harness_defects (#1838). The state file keeps no history, so this is a count, not a trend
flaky_rerunsdailyrecurrences of quarantined checks last seen in the window (issues lists them)one gh search issues over the registry's owners, kept to bug issues carrying quarantine-report.js's <!-- quarantined-check: … --> marker (#1979), bucketed by last seen
ci_durationeventsmedian seconds of completed runs in the window (runs; truncated at 100)gh run list --repo <owner/repo>, updatedAt − startedAt
releasesdailyvX.Y.Z tags cut in the window (latest beside it)git for-each-ref refs/tags, creator date

A project without a GitHub origin remote has ci_duration and flaky_rerunsnot-measured. A missing token log makes all four token and USD series not-measured, naming the file.

Reconciling with token-report ​

A merged requirement's point equals the CLI's total for the same selection:

bash
node scripts/warp-drive/token-report.js --project paulirv/bigbrain --issue 2071 --since 2026-08-15T00:00:00Z --json | jq .totals.usd

--issue <N> (added by #2072) keeps the sessions whose record names requirement N. With no --last, it reports every one of them. --project is a partial match, so name the repo exactly. tests/test-series.js asserts the equality against a fixture token log and git history.

Served by the dashboard ​

bob dash serve (the one dashboard server, scripts/dashboard/server.js) serves the document at /series.json. bob viz draws it on /bob.

BehaviourDetail
RefreshRebuilt at most once every refresh_s seconds (DASH_SERIES_REFRESH_S, default 300), however many tabs poll it: a build runs one issue search and one gh run list per repo. A request that arrives during a build waits for that build instead of starting another.
ClockThe window ends now. DASH_SERIES_NOW (an ISO time) pins it instead, so a test over fixed-date commits stays true as the calendar moves.
Page/bob re-reads /series.json every refresh_s. Each tile on the serving machine gains spend 30d and tokens 30d rows (a sparkline and the total), and the churn strip under the grid shows one row per project: usd_per_merged_req, usd_per_run, fix_to_feat, harness_defect_recurrences, flaky_reruns, ci_duration, releases. Every column sorts, by clicking its header or from the sort by select, and the strip opens sorted by usd_per_merged_req, largest first (#3097).
ghThe forge reads use the server's own gh runner, so they count toward its gh liveness tracker (#1968). An unreadable ci_duration or flaky_reruns carries the server's reason, and the document gains the same gh evidence block as the /warp panes.
Renderscripts/dashboard/bob-series.js, served as /bob/series.js, is a pure function of the document. A sparkline places the points evenly, from 0 to the highest value, with a gap at a null point and a dot on the last known one. A current series is a number, not a line. tests/test-series.js snapshots its output (tests/fixtures/bob-viz/series.html).
FailureIf the document cannot be built at all, the response has projects: [] and an error, and the strip shows the error.

See also ​