Skip to content

Commit 825dd4e

Browse files
committed
Keep measured matrix out of TUnit and gate benchmark quality
1 parent 9567d06 commit 825dd4e

8 files changed

Lines changed: 69 additions & 136 deletions

File tree

‎.github/workflows/performance.yml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ jobs:
109109
run: |
110110
dotnet experiments/Synapse.ReferenceBenchmarks/bin/Release/net10.0/Synapse.ReferenceBenchmarks.dll report \
111111
--input "${RUNNER_TEMP}/synapse-benchmark.json" \
112-
--summary "${GITHUB_STEP_SUMMARY}"
112+
--summary "${GITHUB_STEP_SUMMARY}" --require-quality
113113
114114
- name: Preserve raw per-round evidence
115+
if: always()
115116
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
116117
with:
117118
name: performance-${{ matrix.runtime_identifier }}

‎docs/ADR/ADR-005-benchmark-timing-provenance.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ shared libraries, runtime heaps, and driver memory make that subtraction
3636
invalid. A missing platform metric remains null with its scope recorded.
3737

3838
Functional CI and performance evidence are separate workflows. Functional
39-
tests may make short real-process quality and schema assertions but do not
40-
assert throughput or use long generation as a performance proxy. The manually
39+
TUnit checks can validate rendering against recorded raw evidence, but do not
40+
run the measured matrix or assert throughput. The manually
4141
dispatched performance workflow runs its own macOS/Linux/Windows matrix and
42-
retains every measured round as an artifact with a descriptive report. Hosted
42+
retains every measured round as an artifact with a descriptive report. An
43+
output mismatch fails the job after writing the report, while the raw artifact
44+
is still uploaded. Hosted
4345
runners are variable hardware, so their results are never pooled across OSes
4446
or compared to the owner's Mac as a release winner verdict.
4547

‎docs/Features/Benchmarking.md‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,22 @@ the 30-pair randomized release benchmark, and 8-token decode timing remains
5757
too short for an optimization win claim.
5858

5959
GitHub Actions keeps correctness and performance separate. `verify.yml` runs
60-
the functional suite on macOS ARM64, Ubuntu x64, and Windows x64; its matrix
61-
smoke checks short-output quality and schema, not speed thresholds.
60+
the functional suite on macOS ARM64, Ubuntu x64, and Windows x64; it does not
61+
run the measured matrix or enforce speed thresholds. Existing recorded JSON
62+
tests report formatting and mismatch rejection without running performance
63+
samples inside TUnit.
6264
`performance.yml` is a separate manually dispatched three-OS CPU matrix. It
6365
fetches only the pinned Qwen smoke GGUF, builds the pinned competitors, runs
6466
three warm-ups plus five measured fresh-process rounds with a two-thread cap,
6567
and uploads unmodified per-round JSON for each runner. The C# `report --input
66-
<raw.json> [--summary <path>]` command renders workload, model digest,
68+
<raw.json> [--summary <path>] [--require-quality]` command renders workload, model digest,
6769
platform, quality, median process wall time, peak RSS, Mac footprint, and
68-
reported decode phase into the GitHub job summary. Each runner is a distinct
70+
reported decode phase into the GitHub job summary. The quality flag fails a
71+
job when output diverges, while the raw artifact is retained. Each runner is a distinct
6972
cohort; this eight-token diagnostic neither replaces long generation nor
70-
passes the 30-pair release benchmark gate. A run has not been verified until
71-
its actual Actions job and artifact succeed.
73+
passes the 30-pair release benchmark gate. The first actual Actions run on
74+
`9567d06` passed all three performance jobs and published three raw artifacts;
75+
the quality-gate CLI change still requires a fresh workflow run.
7276

7377
Two 10-turn modes use `benchmarks/scenarios/travel-planner-10-turns.json`:
7478

‎experiments/Synapse.ReferenceBenchmarks/DiagnosticMatrixReportCommand.cs‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ internal static class DiagnosticMatrixReportCommand
99

1010
public static async Task<int> RunAsync(string[] arguments)
1111
{
12-
if (arguments.Length is not (2 or 4) || arguments[0] != "--input" ||
13-
(arguments.Length == 4 && arguments[2] != "--summary"))
12+
var requireQuality = arguments.LastOrDefault() == "--require-quality";
13+
var optionLength = arguments.Length - (requireQuality ? 1 : 0);
14+
if (optionLength is not (2 or 4) || arguments[0] != "--input" ||
15+
(optionLength == 4 && arguments[2] != "--summary"))
1416
{
15-
Console.Error.WriteLine("Usage: report --input <matrix.json> [--summary <github-step-summary>]");
17+
Console.Error.WriteLine("Usage: report --input <matrix.json> " +
18+
"[--summary <github-step-summary>] [--require-quality]");
1619
return 2;
1720
}
1821

@@ -22,11 +25,18 @@ public static async Task<int> RunAsync(string[] arguments)
2225
using var document = await JsonDocument.ParseAsync(stream).ConfigureAwait(false);
2326
var report = Render(document.RootElement);
2427
Console.Write(report);
25-
if (arguments.Length == 4)
28+
if (optionLength == 4)
2629
{
2730
await File.AppendAllTextAsync(arguments[3], report).ConfigureAwait(false);
2831
}
2932

33+
if (requireQuality && document.RootElement.GetProperty("status").GetString() !=
34+
"measured_diagnostic_no_statistical_verdict")
35+
{
36+
Console.Error.WriteLine("Performance evidence is ineligible because quality did not match.");
37+
return 3;
38+
}
39+
3040
return 0;
3141
}
3242
catch (Exception exception)

‎synapse.brainstorm.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ Date: 2026-09-27. Status: accepted for the bootstrap slice.
6868

6969
- Keep functional `verify` fast and assertion-oriented. A long, exact Qwen
7070
continuation is not portable evidence of a quality regression when CPU
71-
kernels choose a different valid sequence; test rejection with an impossible
72-
reference token instead.
71+
kernels choose a different valid sequence. Validate report and quality-gate
72+
behavior from preserved raw evidence in TUnit; run the real matrix only in
73+
the performance workflow.
7374
- Dispatch performance independently on macOS, Linux, and Windows. Preserve
7475
each runner's raw process samples and render a descriptive summary of the
7576
workload and medians. Hosted-runner results form separate hardware cohorts;

‎synapse.plan.md‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,15 @@ gate and remote CI are not verified. No `TASK-BMK-001` release claim is closed.
129129
CI separation follow-up: Ubuntu `verify` on `3bbd5ee` ran 73 tests with one
130130
failure because a functional assertion required a platform-specific 32-token
131131
dotLLM divergence; the same test timed out after five minutes on hosted macOS.
132-
The quality-gate regression now uses an impossible expected token in an
133-
eight-token run, and the performance measurements are in a distinct
134-
manual Mac/Linux/Windows Actions workflow with raw artifacts and a C# report.
132+
The measured matrix is now removed from TUnit entirely: tests use recorded raw
133+
evidence for report and quality-gate behavior. Performance measurements are
134+
in a distinct manual Mac/Linux/Windows Actions workflow with raw artifacts
135+
and a C# report.
135136
The report behavior test was red (unknown `report` command) before the renderer
136-
was added. Three-OS CI execution, artifact publication, and the statistical
137-
release gate remain unverified until the new run completes.
137+
was added; the quality gate was separately red (usage exit 2) before its exit-3
138+
implementation. The first three-OS performance run (`9567d06`) passed and
139+
published three raw artifacts; Windows and Ubuntu verify passed while hosted
140+
Mac verify was still running at this checkpoint. The quality-gate follow-up
141+
and statistical release gate remain unverified until new runs complete.
138142
- [ ] Execute Qwen2 from the verified region IR instead of the parallel shadow
139143
loop, following `flybrain.plan.md` F0/F1 and accepted ADR-003.

‎tests/Synapse.IntegrationTests/Features/Benchmarking/DiagnosticMatrixReportTests.cs‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,30 @@ public async Task RawMatrixEvidenceProducesDescriptivePerformanceReport()
3535
await Assert.That(report).Contains("peak RSS MiB");
3636
await Assert.That(report).Contains("Measured rounds: 5");
3737
}
38+
39+
[Test]
40+
public async Task IneligibleRawEvidenceFailsPerformanceQualityGate()
41+
{
42+
var root = FindRepositoryRoot();
43+
var evidence = Path.Combine(root, "benchmarks", "results",
44+
"2026-09-28-m2-pro-qwen2.5-0.5b-q8_0-32tok-quality-divergence-final.json");
45+
var start = new ProcessStartInfo("dotnet")
46+
{
47+
RedirectStandardOutput = true,
48+
RedirectStandardError = true,
49+
UseShellExecute = false,
50+
};
51+
start.ArgumentList.Add(Path.Combine(AppContext.BaseDirectory, "Synapse.ReferenceBenchmarks.dll"));
52+
start.ArgumentList.Add("report");
53+
start.ArgumentList.Add("--input");
54+
start.ArgumentList.Add(evidence);
55+
start.ArgumentList.Add("--require-quality");
56+
using var process = Process.Start(start)
57+
?? throw new InvalidOperationException("Matrix report process did not start.");
58+
var output = process.StandardOutput.ReadToEndAsync();
59+
var error = process.StandardError.ReadToEndAsync();
60+
await process.WaitForExitAsync().WaitAsync(TimeSpan.FromSeconds(30));
61+
await Assert.That(process.ExitCode).IsEqualTo(3).Because(await error);
62+
await Assert.That(await output).Contains("ineligible_quality_mismatch");
63+
}
3864
}

‎tests/Synapse.IntegrationTests/Features/Benchmarking/DiagnosticMatrixSmokeTests.cs‎

Lines changed: 0 additions & 115 deletions
This file was deleted.

0 commit comments

Comments
 (0)