Skip to main content

abc report

Researcher-productivity summary read entirely from ~/.abc/db/local.db. No network calls — abc report is a seed-tier-native command.

Usage

abc report # personal YTD summary, default text mode
abc report --since=2026-01-01 --until=2026-04-30
abc report --show-rate-card # append the full per-rate provenance block
abc report --json # machine-readable; metric IDs as keys
abc report --json --by=investigation
abc report --technical # metric IDs replace human Titles

abc report runs # per-run cost + emissions table (subverb)
abc report runs --full # forensic per-row block (run_id, nomad job, …)

Flags

FlagDefaultDescription
--since=YYYY-MM-DDJan 1 of current yearWindow start (UTC)
--until=YYYY-MM-DDnowWindow end (inclusive end-of-day)
--by=<axis>unsetAggregation axis: investigation / project / pipeline / user. JSON-only in v1; text mode rejects with a "deferred to v2" message.
--show-rate-cardfalseAppend the detailed per-rate provenance block (currency, CPU/GPU/memory/storage cost rates, all emissions coefficients) + override hints. Hidden by default — the headline already carries a "rates are suggestive default values" disclaimer.
--jsonfalseEmit the structured JSON contract documented below
--technicalfalseReplace human Titles with metric IDs in the text headline (useful for reproducible doc snippets)
--all-contextsfalseCross-context aggregation. Phase 2: rejects with --all-contexts requires abc-controller-svc; not available in this context. (gated until the controller service is deployed)

Default output is cost + emissions only (2026-05-27). The "Research time saved" heuristic block was removed from the default render pending real measurement (see the "Research time saved" section below). The detailed rate card moved behind --show-rate-card.

Two-layer metric naming

Every metric has a stable technical ID (frozen at first ship; used in JSON keys, --by flag values, SQL view names, and manuscript scripts) plus a revisable user-facing Title and Gloss (revisable without an ADR).

IDTitleGloss
mttfsFirst-success timeHow long from first attempt to first working run
failure_to_result_ratioFailed runs per resultHow many tries it took to get a usable answer
retry_depthTries before successAttempts before the run worked
mttr_failureRecovery timeHow fast you got back on track after a failure
stabilisation_runsRuns to settleSubmissions before the pipeline ran reliably
queue_wait_fractionWaiting in queueShare of total time spent waiting, not running
active_engagement_hoursHands-on timeHours actually at the terminal
spectator_hoursWatching timeHours spent monitoring runs
async_job_fractionWalked-away runsRuns you submitted and didn't babysit
cognitive_overhead_scoreTools per workflowDistinct commands touched to get one result
workflows_unattendedHands-off completionsPipelines that finished without you stepping in
submission_sourceSubmission sourceHow the run was authored: template / handwritten / rerun
resource_fitRight-sized requestsHow close requested CPU/RAM matched what was used
cost_per_investigationSpend per questionZAR per investigation, resolved via internal/accounting rate card
emissions_per_investigationCarbon per questionkg CO₂e attributed to each investigation, resolved via internal/emissions
spend_zarTotal spendWindow-wide ZAR aggregate, computed via the shared internal/accounting rate-card resolver
emissions_kgco2eTotal emissionsWindow-wide kg CO₂e, computed via the shared emissions resolver
hours_savedResearch time savedHeadline composite: estimated busywork avoided

Adding a metric requires populating all four fields (ID, Title, Gloss, Unit) in the same patch. The ID contract is enforced by tests; titles are capped at 32 characters.

Research time saved (heuristic; JSON / --show-rate-card only)

Removed from default text output (2026-05-27). The hours_saved family is a set of compile-time heuristics (counts of auto-retries, accepted defaults, etc. × hardcoded minute-multipliers) not yet backed by real measurement, so presenting it as a headline number was misleading at the seedling tier. The default abc report now shows only cost + emissions. The metric is still computed and exposed in the JSON contract (metrics.hours_saved) for downstream consumers; a future instrumented version may return to the text view behind its own flag.

The hours_saved heuristic is the sum of five compile-time constants:

ConstantMinutes saved per applicable runSource
AutoRetrySavedMinutes15brainstorm §5.10; manual re-submit round-trip
SmartDefaultSavedMinutes10resource_fit metric rationale
FailureSummarySavedMinutes30structured failure summary vs. log diving
TemplateReuseSavedMinutes60template / rerun vs. setup from scratch
AsyncRunSpectatorAvoidedMin30spectator_hours; median observed monitoring session

One ledger, one read-side command

abc report is the canonical read-side surface over the local SQLite runs ledger. The Layer-0/1/2 rate-card resolver (internal/accounting) and the grid-intensity resolver are consumed directly here; the prior abc accounting report and abc emissions [report] commands were folded into this single closed-loop output (spec cli-verb-tree-restructure).

abc report --since=… --until=…

produces spend, emissions, and postdoc-hours-returned together, with per-investigation rollups. For namespace-budget management (the write-side, admission-gate surface), see abc accounting.

Subcommands

abc report also hosts the dedicated environmental-footprint reports, folded in from former top-level verbs on 2026-06-05:

CommandWasPurpose
abc report emissionsabc emissionsCO₂e report (Cloud Carbon Footprint v3 coefficients)
abc report waterabc waterfreshwater report (Green Grid Program-WUE formula)
abc report runsper-run cost + emissions ledger
abc report compliancecompliance status from the ABC API

All share the same Layer-0/1/2 rate-card resolver, so energy/cost/CO₂e/water figures stay consistent. Rate-card inputs are configured under abc config emissions (coefficients) and abc config accounting (cost rates) — distinct from the read-side reports here.

Sample output

Default — cost + emissions headline only:

$ abc report
Your 2026 so far:
────────────────────────────────────────────────────
Questions explored (investigations): 3
Pipeline runs: 12 (10 worked, 2 retried)
Total compute: 47 CPU-hrs, 0 GPU-hrs

Spend this period: R 1,420
Emissions this period: 47.3 kg CO₂e

These rates are suggestive based on the reasonable default values,
the real-time rates are coming soon.

With --show-rate-card — appends the full per-rate provenance block:

$ abc report --show-rate-card
[ … headline blocks as above … ]

Rate card (effective):
currency ZAR built-in (SA market default)
cost.cpu_hour 0.5 built-in (abc-cluster-cli vX — SA on-prem indicative)
cost.gpu_hour 9 built-in (abc-cluster-cli vX — SA on-prem indicative)
cost.memory_gb_hour 0.05 built-in (abc-cluster-cli vX — SA on-prem indicative)
cost.storage_scratch_gb_hour 0.0001 built-in (amortised enterprise NVMe + power)
cost.postdoc_per_hour 350 built-in (HSRC 2025 SA postdoctoral compensation guidance)
emissions.grid_factor_gco2_per_kwh 900 built-in (Eskom Integrated Annual Report 2023)
emissions.cpu_w 12 built-in (Cloud Carbon Footprint v3 coefficient set)
emissions.gpu_w 250 built-in (Cloud Carbon Footprint v3 coefficient set)
emissions.memory_gb_w 0.3725 built-in (Cloud Carbon Footprint v3 coefficient set)
emissions.pue 1.5 built-in (Uptime Institute 2023 — generic on-prem average)
emissions.storage_scratch_w_per_tb 8 built-in (Samsung PM9A3 envelope amortised)

These rates are suggestive based on the reasonable default values,
the real-time rates are coming soon. To override locally:
abc config accounting set cost.postdoc_per_hour=400
abc config emissions set pue=1.27 grid_factor_gco2_per_kwh=950

The provenance footer is generated from the resolved rate card — every value carries its layer (built-in / local / flag) and citation. A Layer-1 override in ~/.abc/config.yaml (e.g. cost.postdoc_per_hour: 525) flows through the same resolver abc accounting uses. One ledger, two lenses (abc report for showback, abc accounting for budget caps).

abc report runs — per-run cost + emissions

Lists one row per submitted job/pipeline with cost + emissions derived from the stored resources × the rate card. Jobs sort first (most-recent within), then pipelines. Reads ~/.abc/db/local.db; re-probes Nomad for runs whose completion watcher died (the CLI exits seconds after submission, but jobs take minutes) unless --no-reconcile is passed.

abc report runs # last 30d, 20 rows, jobs first
abc report runs --since=7d --limit=50
abc report runs --verb=job # jobs only (no pipeline footnote)
abc report runs --verb=pipeline # pipelines only
abc report runs --full # per-row forensic block
abc report runs --json # machine-readable
abc report runs --no-reconcile # skip the Nomad re-probe (faster offline)
$ abc report runs --since=30m
Runs · 2026-05-27 → 2026-05-27
────────────────────────────────────────────────────────────────────────────
TIME (UTC) VERB WORKLOAD CPU·hr COST(R) CO₂e (kg) STATUS
2026-05-27 13:30 job cpu-burn.sh 0.33 0.17 0.01 completed
2026-05-27 13:25 job timed-30.sh 0.01 0.00 0.00 completed
2026-05-27 13:30 pipeline nextflow-io/hello 0.02 — — completed

(—) Pipeline cost/emissions are pending: the head-orchestrator's
resources alone undercount the real pipeline by 10-100×, so the
numbers are intentionally blank until the per-task cache aggregator
ships. Job rows are computed directly from Nomad alloc resources
and are honest.

Jobs are honest; pipelines are head-only today. A job is a single Nomad alloc — the watcher reads its resources and the cost is accurate. A pipeline is a head orchestrator that dispatches many worker jobs the watcher doesn't yet sum, so pipeline cost/emissions cells render until the Nextflow-cache aggregator lands. --full adds a per-row vertical block surfacing run_id, nomad_job_id, namespace, exit_code, exit_reason, project / investigation attachments, and (for pipelines) workdir_root — useful for tracing a row to its Nomad job (abc job show <nomad_job_id>).

JSON schema

{
"window": {"since": "<RFC3339>", "until": "<RFC3339>"},
"context_name": "abc-dev",
"metrics": {
"<metric-id>": {
"id": "<metric-id>",
"label": "<human Title>",
"gloss": "<one-line gloss>",
"unit": "hours|count|percent|currency",
"value": <number | object>,
"computable": true,
"reason": "(present only when computable=false)"
}
},
"rate_card": {
"currency": {"value": "ZAR", "source": "built-in", "citation": "SA market default"},
"cost.cpu_hour": {"value": 0.5, "source": "built-in", "citation": "abc-cluster-cli vX — SA on-prem indicative"},
"cost.gpu_hour": {"value": 9, "source": "built-in", "citation": "..."},
"cost.memory_gb_hour": {"value": 0.05, "source": "built-in", "citation": "..."},
"cost.storage_scratch_gb_hour": {"value": 0.0001, "source": "built-in", "citation": "..."},
"cost.postdoc_per_hour": {"value": 350, "source": "built-in", "citation": "HSRC 2025 SA postdoctoral compensation guidance"},
"emissions.grid_factor_gco2_per_kwh": {"value": 900, "source": "built-in", "citation": "Eskom IAR 2023"},
"emissions.cpu_w": {"value": 12, "source": "built-in", "citation": "CCF v3"},
"emissions.gpu_w": {"value": 250, "source": "built-in", "citation": "CCF v3"},
"emissions.memory_gb_w": {"value": 0.3725, "source": "built-in", "citation": "CCF v3"},
"emissions.pue": {"value": 1.5, "source": "built-in", "citation": "Uptime Institute 2023"},
"emissions.storage_scratch_w_per_tb": {"value": 8, "source": "built-in", "citation": "Samsung PM9A3 envelope"}
},
"groups": [ // present only when --by=<axis> set
{
"by": "investigation",
"key": "inv-abc",
"metrics": { "<metric-id>": { ... } }
}
]
}

Required substrate (migrations)

abc report reads existing columns where available and gracefully degrades to "n/a (reason)" otherwise.

MigrationAddsUnlocks metric
0008_runs_queue_waitpending_secondsqueue_wait_fraction
0009_runs_resource_requestcpu_request, mem_request_gbresource_fit
0010_runs_submission_sourcesubmission_sourcesubmission_source, contributes to hours_saved

Run abc localdb migrate to apply pending migrations. abc localdb status lists feature flags advertised through the capability layer.

No network guarantee

abc report declares Required{ AllOf: [{Service: "local-state"}] } — the local-state pseudo-service derived from the migration framework. The command makes zero outbound HTTP calls in any code path. A test in cmd/report/report_test.go swaps http.DefaultTransport for a tripwire and asserts zero RoundTrip calls during render.

Capability layer

NeedBackendAvailable
AllOf local-statelocal SQLiteseed (always)
--all-contextsabc-controller-svc (federation-aggregate)controller servicegated; rejects until controller service is reachable

--all-contexts rejects with the standard capability.Require failure message when the controller service isn't deployed in the active context's capabilities map.

See also

  • abc accounting — write-side namespace budget caps and admission-gate thresholds (grove tier and above).
  • abc localdb status — schema version, applied migrations, feature flags.