# What 150 Watts Buys — data kit

**What this directory holds.** Every receipt behind the exhibit *What 150 Watts
Buys* (https://research.strata2signal.com/what-150-watts-buys/index.html): the
twelve rungs of the power-cap arm exactly as the harness recorded them, the
noise floor the verdicts are read against, and the two rows from the morning
serving bench the exhibit compares them to. One card — a **96 GB workstation
card** — on one day, **2026-08-25**, at two board power limits: its 600 W default
and 450 W. Nothing else changed between the two.

The arm opened **2026-08-25T19:18:55Z** and its last rung closed
**2026-08-25T19:44:12Z**. The `reference/` rows are from earlier the same day,
**10:48:41Z – 10:56:50Z**.

**Licence: CC BY 4.0.** Take these rows, re-plot them, check our arithmetic,
publish what you find. Attribution: strata→signal research,
research.strata2signal.com. If you find an error in any of this, we want to hear
about it: hello@strata2signal.com.

## What is in here

Eighty-three files in four groups. `index.json` lists every one of them with its
size and sha256; this table says what each *kind* of file is. The fourth group,
`ladder/`, is a **second sitting** — see "The cap ladder" below before you read
any of its rows beside the twelve rungs'.

| file | what it holds | what was applied to it |
|---|---|---|
| `rungs/<rung>/summary.json` | One rung's identity and its aggregate result: the arm, the limit, the concurrency, the UTC window it ran in, the frozen prompt's sha256, the harness's own sha256, and the per-concurrency row — requests, time-to-first-token p50/p95/min/max, tokens a second per stream and aggregate, tokens seen. Also the rung's own power-window summary as the harness computed it. | `bench-slug-to-class`, `endpoint-to-role`, `harness-host-to-role`, `absolute-path-to-filename` |
| `rungs/<rung>/power.csv` | The card's own power stream for that rung, one sample every ~0.5 s: UTC timestamp, draw in watts, SM clock in MHz, temperature in °C, memory used in MiB, utilisation in per cent. This is where every watt, degree and clock figure on the page comes from. | `csv-timestamps-to-utc`, `header-row-to-line-1` |
| `rungs/<rung>/throttle.csv` | The card's own throttle stream, one sample every ~0.5 s: UTC timestamp, the raw event-reason bitmask, six named reason **flags** (`Active` / `Not Active`), the cumulative power-cap **counter** in microseconds, and the current SM clock. The half-failed instrument. These streams run well past the end of their rung — see "why these files are long" below. | `csv-timestamps-to-utc` |
| `rungs/<rung>/throttle-delta.json` | The cumulative counter read once before the rung and once after, with the difference. Twelve of twelve read a delta of zero. | none — byte for byte |
| `rungs/<rung>/raw.jsonl` | Every request this bench paid, one JSON object per line: which stream and repeat it was, send / first-token / last-token instants, prompt and completion token counts, finish reason, the sha256 of the reply text, and the derived time-to-first-token and decode rate. Failures would appear here with `ok: false`; there are none. | none — byte for byte |
| `noise-floor.md` | The same-cap repeat table — the spread two identical runs at one limit produce — and the pre-registered rule that a cross-cap difference smaller than that spread is not a result. Read it before you read any difference in this kit. | authored for publication |
| `NOTES.md` | The measurement record: what was varied, every headline figure with the directory it comes from, the flag-versus-counter finding with its counts, and the two comparisons this data does not support. | authored for publication |
| `reference/<arm>/…` | The morning serving bench's two dense rows — the arm the exhibit's "hottest arm" comparison is read from, with its own `summary.json` and `power.csv`. Present so the 594.6 W / 87 °C / eight-minute-leg sentence can be checked rather than taken on trust. | same rules as `rungs/` |
| `ladder/…` | The 2026-08-27 cap ladder on the image lane, a separate sitting with its own registration: `PREREG-CAP-LADDER-0827.md` (registered before the first scored render, with four dated amendments), `sample.json` (the sealed 139-cell registry, sha-pinned in the registration), `rows.jsonl` (605 renders, one per line, with the render engine's own execution stamps), `llm-rows.jsonl` (the serving lane probed at each rung), `power-600W.csv` / `power-500W.csv` / `power-450W.csv` (each sample carrying the board limit it was taken under), `perf-600W.txt` / `perf-500W.txt` / `perf-450W.txt` (the one-shot `nvidia-smi -q` flag reads taken at each rung's open, inside each lane's block, and at its close), and the two arms' completion notes. | its own pass — `ladder/provenance-ladder.json`, published verbatim |
| `provenance.json` | Every file above with both sha256s, the named rules applied to it and how many times each one fired, plus the software versions the run stood on. | — |
| `index.json` | This directory, listed: file names, sizes, sha256s, and what each one answers. | — |

## The cap ladder — a second sitting, not more of the first

`ladder/` holds a **different measurement on the same card**: on **2026-08-27**,
**16:19–18:14Z**, the image lane was walked down the dial — 600 → 500 → 450 W —
with the same 139 sealed cells rendered at each rung. It arrived in this kit at
the exhibit's release rather than at the bench's, and it is the evidence behind
the page's "Same dial, other lane" section and the ruling that put the dial at
500 W.

**Its rows must not be pooled with the twelve rungs above.** Different day,
different lane, different cell set, its own registration and its own gates. Two
things follow from that and are stated here rather than left to be discovered:

- The ladder's **600 W rung is the only baseline** its percentages are read
  against. The earlier sitting of 2026-08-23 predates this card moving onto a
  sine-wave UPS, and the page publishes the ~6 % environment drift between the
  two sittings as an observation rather than a controlled result.
- The ladder was **sanitised by its own pass**, whose record is published
  verbatim as `ladder/provenance-ladder.json` and carried per file in this kit's
  `provenance.json`. That record names two kinds of count — per-rule
  (`<file>:<rule>`) and one unattributed count keyed by the bare filename — and
  `provenance.json` carries both without reconciling them. `sample.json`'s 88
  substitutions are unattributed in the record as written, and both files say so
  rather than assigning them a rule.
- The three **`perf-<arm>.txt` flag reads** arrived later than the rest of the
  ladder — they were added to this kit on **2026-08-28**, in the re-cut that
  repaired `llm-rows.jsonl` (below) — so they were sanitised by THAT pass and not
  by the ladder's own. `ladder/provenance-ladder.json` is the 2026-08-27 record
  and does not mention them; their rule and its count are in this kit's
  `provenance.json`, under `nvsmi-timestamp-to-utc`. Read them with the arm notes:
  each file is a handful of instantaneous reads, and the arm notes say in their own
  words why a single read is sampling luck rather than evidence at this granularity
  — the power CSV beside it is what binds.

**One row of `ladder/llm-rows.jsonl` was repaired on 2026-08-28, and the repair is
named here rather than made quietly.** Line 20 — the 450 W arm's third gemma call —
reached this kit with a substitution written INTO its `prompt_eval_duration_ns`
value. The ladder's `port-to-role` pass had matched the port number `11435` inside
the nanosecond measurement `114356000` and replaced it with that seat's role
string, so the field read as a role string with the measurement's last four digits
stranded on the end of it — not a number, not valid JSON, and the only unparseable
line in this kit. The true value,
`114356000`, is restored from the run's own results, and it checks against the row's
other published fields: 536 prompt tokens over 0.114356 s is 4687.117 tokens a
second, which is exactly the `prefill_tok_s` that row already carried. Nothing else
on the line moved, and the row's `port` keeps the role string the sanitiser correctly
wrote. The `port-to-role` count in `ladder/provenance-ladder.json` — 49 fires in this
file — is left as the pass wrote it, because that is what the pass did; one of those
49 was this mistake.

## What it ran on

A **96 GB workstation card** at **driver generation 595**, with **vLLM 0.27.1**
(transformers 5.14.1, torch 2.13.0+cu130) and **Ollama 0.32.15**. The versions are
here rather than only on the page because the exhibit's instrument finding — the
flag and the counter disagreeing — is specific to this driver generation, and a
reader on the next one has no way to re-check it otherwise. They are repeated in
`provenance.json` under `instrument`, with a note on where they were read from.

**4,044 scored requests, 0 failed**, across the twelve rungs.

## The three rules you need to recompute anything here

1. **Window each rung to its own clock.** Every `power.csv` and `throttle.csv`
   covers more than its rung. Use the `started_utc` and `ended_utc` in that
   rung's own `summary.json` as the window, and count only samples inside it.
   A count taken over a whole stream is not a count of that rung. Compare the
   **whole** timestamp, sub-seconds included — a `summary.json` window is stated
   to the second, and truncating a sample's sub-seconds to match it pulls one
   extra sample in at each end (275 in-window throttle samples on the clamped
   rung become 277, and the kit stops reproducing the page over two rows of
   rounding).
2. **The busy window is utilisation ≥ 50 %.** Where this kit and the exhibit
   say "busy mean", they mean: average only the `power.csv` samples whose
   `utilization.gpu` column reads **50 or more**, so idle gaps between requests
   don't flatter the number. The same rule is used for every busy figure on the
   page, in both directions — it never switches denominators between a glossary
   and a headline.
3. **A cross-cap difference smaller than the noise floor is not a result.**
   `noise-floor.md` is that floor, measured rather than assumed.

## About the timestamps

The harness wrote its two CSV streams with a **local wall-clock** stamp while
every other record in this bench is UTC. That mismatch is not a footnote here —
an unconverted window is exactly what produced this bench's first, wrong verdict,
and the exhibit is partly about catching it. **The copies in this kit have those
stamps converted to UTC and Z-stamped**, so every file in this directory is on
one clock and a rung's CSV can be windowed against its own `summary.json` — by
PARSING both instants. Do not compare them as strings: a `summary.json` bound is
stated to the second, a sample is stamped to the sub-second, and a plain string
comparison pulls in the partial end-second and turns 275 in-window throttle samples
on the clamped rung into 276. Row counts, row order and every other column are
untouched — `provenance.json` prints how many stamps were converted in each file
so you can check that only the first column moved.

If you are ever reading this harness's raw output somewhere other than this kit:
**the CSV timestamps are LOCAL, not UTC — convert before windowing.**

## Why the throttle files are long

Each rung's throttle sampler was started when its rung began and was never
stopped when the rung ended — all twelve were still running when the session
closed. So each `throttle.csv` begins at its own rung and then keeps recording
long after it, and by the end of the run twelve samplers were writing at once.
The overlap is real instrument behaviour, not duplication for its own sake, and
it is load-bearing: the cumulative counter that read zero through the whole bench
**resumes** inside these streams, at 2026-08-25T20:05:03.992Z. Truncating them to
their rungs would have removed the only evidence that the counter was stalled
rather than broken.

## Sanitised at the pen, not copied

Nothing here is a raw copy of a file that named a machine. Each file was read and
rewritten, and every transform has a NAME that `provenance.json` prints per file
with the number of times it fired — so a reader can see which rules touched a
file and be sure nothing else did. The rules, in full:

- **`bench-slug-to-class`** — the run's internal slug named the card's model
  number. It becomes the class: the `bench` field reads `power-cap-96gb`. No
  measurement changes.
- **`endpoint-to-role`** — the private address the harness called becomes the
  role it played: `<serving host>`. What was served, and how, is unchanged and
  fully stated in the same file.
- **`harness-host-to-role`** — the machine that drove the bench becomes
  `<harness host>`. It is a different machine from the card under test, which is
  why it is worth saying it existed at all.
- **`absolute-path-to-filename`** — a directory path pointing into a private
  filesystem becomes the file's own name, `power.csv`, which is what it means in
  this kit anyway.
- **`csv-timestamps-to-utc`** — the first column of every `power.csv` and
  `throttle.csv` is converted from the harness's local wall clock to UTC and
  Z-stamped. Only that column changes; no row is added, dropped or reordered.
- **`header-row-to-line-1`** — the harness wrote each `power.csv` header row
  *last*, which makes the file unreadable to anything that expects a header
  first. The line is moved to the top, byte for byte, and no other line moves.
  `throttle.csv` already carried its header first and was not touched this way.
- **`nvsmi-timestamp-to-utc`** — the three `ladder/perf-<arm>.txt` flag reads are
  `nvidia-smi -q` output, and the driver writes its `Timestamp` line in the host's
  local wall clock. Each one is re-stated in UTC — same instant, same `nvidia-smi`
  date format, with the frame named — using the offset read off that block's own
  harness stamp. Twenty-two stamps in three files; every other line of those files,
  including the counters and the flag states, is published exactly as the driver
  printed it.

**One file was left out rather than rewritten.** Each rung also produced a
`run.log` — a human-readable echo of the harness's settings. It prints the
address it called and the name of the machine that sampled power, and everything
in it that is a measurement is already in `summary.json`, so it is omitted rather
than redacted into something nobody wrote. Said plainly here rather than implied
by its absence.

**The frozen prompt's TEXT is not in this kit either, and that is a second
omission worth naming.** Every rung was driven against one frozen prompt, `p512`,
and its sha256 — `90eedd0c53f9554ae3837674504fcb7090013d9a432a653352183c0f25a7ce5c`
— is printed on the exhibit page, in every rung's `summary.json`, and in the cap
ladder's registration, so the prompt this bench ran is pinned and a holder of the
same file can prove they have it. The bytes themselves are held pending a
licensing call on the source text, and are published nowhere on this site. What
that costs a reader is stated plainly rather than left to be found: you can
verify a copy of the prompt you already hold, and you cannot reconstruct it from
this kit. If it clears, it ships here and this paragraph says so.

**What was not touched.** Every wattage, clock, temperature, token count, latency
and UTC instant is published as recorded. No row was dropped, reordered or
resampled. No failed request was excluded, because none failed.

## What these rows will and will not tell you

They record **what**, not **why**. They record how fast each lane wrote and what
the card drew while it did, at two board power limits — and they record that the
card's throttle flag and its throttle counter disagreed. They do not explain the
mechanism behind the dense lane's 2.0 %; the exhibit names memory-bandwidth-bound
decoding as the reason and does not claim to have isolated it.

The dense lane was measured **once** at each limit. Its difference is read against
the *sparse* lane's repeat spread — a borrowed denominator, and a weaker claim
than the sparse lane's own.

## Not a standard

Twelve rungs on one card, on one day, with one prompt, at two limits, sized to one
question: what does a lower board power limit cost the two seats this workshop
actually runs? It is not a leaderboard and not a benchmark suite. A different
model, a different quantisation, a different prompt length or a different card
will land somewhere else, and the numbers here are not evidence about any of them.
