fm-bench 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,7 +30,7 @@ fm-bench
30
30
  One command discovers your models, runs the standard prompt suite, and prints a full benchmark report:
31
31
 
32
32
  ```text
33
- fm-bench 0.6.0 | darwin/arm64 | fm
33
+ fm-bench 0.6.2 | darwin/arm64 | fm
34
34
  prompts 3 | runs 5 | concurrency 1 | stream on | measured 15 | failed 0 | skipped 0 | elapsed 38.20s
35
35
 
36
36
  ┌───┬────────┬────────┬─────────┬──────┬──────┬──────────┬──────┬──────────┬─────┬─────┐
@@ -12,7 +12,7 @@ Every measured run can be saved as JSON. Reports from fm-bench **0.6.0+** includ
12
12
  | `reportId` | Random hex id for citing a single run |
13
13
  | `startedAt` / `finishedAt` | ISO-8601 timestamps |
14
14
  | `options` | Public run configuration (profile, runs, concurrency, SLOs, tags, note) |
15
- | `environment` | Host fingerprint: platform, arch, Node, hardware model, CPU, memory, macOS version, `fm` help digest, thermal/power snapshot |
15
+ | `environment` | Host fingerprint: platform, arch, Node, hardware model, CPU, memory, macOS version/build, `fm` help digest, thermal/power snapshot |
16
16
  | `suite` | Derived suite key + fingerprint for apples-to-apples comparison |
17
17
  | `prompts` | Prompt ids, text, and token counts |
18
18
  | `models` | Discovered models and availability |
@@ -38,6 +38,7 @@ For fair comparison, match:
38
38
  - Same `--profile` (or same `--prompt-file`)
39
39
  - Same `--runs` and `--warmup`
40
40
  - Same concurrency operating points (`--concurrency` or `--sweep-concurrency`)
41
+ - Same or intentionally changed macOS build (especially for beta-to-beta comparisons)
41
42
  - Similar power/thermal state (see `environment.power` and `environment.thermal`)
42
43
 
43
44
  ```sh
@@ -45,8 +46,8 @@ fm-bench compare before.json after.json
45
46
  fm-bench compare before.json after.json --strict # exit 2 if suites differ
46
47
  ```
47
48
 
48
- `compare` warns when hardware, macOS, or suite configuration differ. Use `--tag` and `--note` so `fm-bench history` stays readable.
49
+ `compare` warns when hardware, macOS product version, macOS build, or suite configuration differ. Use `--tag` and `--note` so `fm-bench history` stays readable.
49
50
 
50
51
  ## Legacy reports
51
52
 
52
- Reports from fm-bench before 0.6.0 remain valid JSON. They lack `schemaVersion`, `reportId`, `suite`, and enriched `environment`. `validate` still checks required fields; `compare` works on `summary` as before.
53
+ Reports from fm-bench before 0.6.0 remain valid JSON. They lack `schemaVersion`, `reportId`, `suite`, and enriched `environment`. `validate` still checks required fields; `compare` works on `summary` as before.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fm-bench",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Dynamic benchmark CLI for Apple's fm command on macOS 27+.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/compare.js CHANGED
@@ -25,6 +25,12 @@ export function diffReports(before, after) {
25
25
 
26
26
  function reportMeta(report) {
27
27
  const tags = report.options?.tags;
28
+ const macOS = report.suite?.fingerprint?.macOSProductVersion
29
+ ?? report.environment?.macOS?.match(/ProductVersion:\s*([^\n]+)/)?.[1]?.trim()
30
+ ?? null;
31
+ const macOSBuild = report.suite?.fingerprint?.macOSBuildVersion
32
+ ?? report.environment?.macOS?.match(/BuildVersion:\s*([^\n]+)/)?.[1]?.trim()
33
+ ?? null;
28
34
  return {
29
35
  version: report.version ?? '?',
30
36
  schemaVersion: report.schemaVersion ?? null,
@@ -37,9 +43,8 @@ function reportMeta(report) {
37
43
  tags: Array.isArray(tags) ? tags : [],
38
44
  note: report.options?.note ?? null,
39
45
  hwModel: report.environment?.hwModel ?? report.suite?.fingerprint?.hwModel ?? null,
40
- macOS: report.suite?.fingerprint?.macOSProductVersion
41
- ?? report.environment?.macOS?.match(/ProductVersion:\s*([^\n]+)/)?.[1]?.trim()
42
- ?? null
46
+ macOS,
47
+ macOSBuild
43
48
  };
44
49
  }
45
50
 
@@ -134,8 +139,8 @@ export function renderCompareReport(diff, options = {}) {
134
139
  const afterLabel = `${diff.after.version} ${diff.after.startedAt ? diff.after.startedAt.slice(0, 19).replace('T', ' ') : '?'}`;
135
140
 
136
141
  lines.push(`fm-bench compare`);
137
- lines.push(` before: ${beforeLabel}${diff.before.hwModel ? ` | ${diff.before.hwModel}` : ''}`);
138
- lines.push(` after: ${afterLabel}${diff.after.hwModel ? ` | ${diff.after.hwModel}` : ''}`);
142
+ lines.push(` before: ${beforeLabel}${diff.before.hwModel ? ` | ${diff.before.hwModel}` : ''}${formatMacOSMeta(diff.before)}`);
143
+ lines.push(` after: ${afterLabel}${diff.after.hwModel ? ` | ${diff.after.hwModel}` : ''}${formatMacOSMeta(diff.after)}`);
139
144
  if (diff.before.profile || diff.after.profile) {
140
145
  lines.push(` suite: profile=${diff.before.profile ?? '?'} runs=${diff.before.runs ?? '?'} (before) → profile=${diff.after.profile ?? '?'} runs=${diff.after.runs ?? '?'}`);
141
146
  }
@@ -221,6 +226,13 @@ export function renderCompareReport(diff, options = {}) {
221
226
  return lines.join('\n');
222
227
  }
223
228
 
229
+ function formatMacOSMeta(meta) {
230
+ if (!meta.macOS && !meta.macOSBuild) return '';
231
+ const label = meta.macOS ? `macOS ${meta.macOS}` : 'macOS';
232
+ const build = meta.macOSBuild ? ` (${meta.macOSBuild})` : '';
233
+ return ` | ${label}${build}`;
234
+ }
235
+
224
236
  function fmtDiffMs(diff, which, color) {
225
237
  const value = diff[which];
226
238
  if (value == null) return '-';
package/src/schema.js CHANGED
@@ -96,6 +96,9 @@ export function compareCompatibility(before, after) {
96
96
  if (bFp.macOSProductVersion && aFp.macOSProductVersion && bFp.macOSProductVersion !== aFp.macOSProductVersion) {
97
97
  warnings.push(`macOS version differs (${bFp.macOSProductVersion} vs ${aFp.macOSProductVersion})`);
98
98
  }
99
+ if (bFp.macOSBuildVersion && aFp.macOSBuildVersion && bFp.macOSBuildVersion !== aFp.macOSBuildVersion) {
100
+ warnings.push(`macOS build differs (${bFp.macOSBuildVersion} vs ${aFp.macOSBuildVersion})`);
101
+ }
99
102
 
100
103
  return {
101
104
  compatible: errors.length === 0,
@@ -155,4 +158,4 @@ function cryptoRandomId() {
155
158
  const bytes = new Uint8Array(8);
156
159
  globalThis.crypto.getRandomValues(bytes);
157
160
  return [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');
158
- }
161
+ }