Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ The release procedure (prompt template and step-by-step instructions) lives in [

## [Unreleased]

### Fixed
- **The `calibrate` goal's paste block mixed line endings on Windows.** `CalibrationReport` wrote its three
value lines with `String.format("...%n")`, the platform line separator, between lines ending in `\n`, so on
Windows the `<calibration>` block meant for a `pom.xml` carried 3x CRLF and 3x LF. All lines end in `\n`
now. `CalibrationReportTest` renders the block in a child JVM started with `-Dline.separator=\r\n`, so the
Linux CI sees what only a Windows build showed before (red without the fix).

### Changed
- Build tooling bumped in step with the sibling repositories: `anthropics/claude-code-action` v1.0.258 and
`github/codeql-action` v4.39.1. maven-clean-plugin 3.5.0, maven-resources-plugin 3.5.0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,11 @@ private static void appendPasteBlock(
out.append("<calibration>\n");
out.append(String.format(
Locale.ROOT,
" <prefillTokensPerSecond>%.1f</prefillTokensPerSecond>%n",
" <prefillTokensPerSecond>%.1f</prefillTokensPerSecond>\n",
m.prefillTokensPerSecond()));
out.append(String.format(
Locale.ROOT, " <decodeTokensPerSecond>%.1f</decodeTokensPerSecond>%n", m.decodeTokensPerSecond()));
out.append(String.format(Locale.ROOT, " <charsPerToken>%.2f</charsPerToken>%n", m.charsPerToken()));
Locale.ROOT, " <decodeTokensPerSecond>%.1f</decodeTokensPerSecond>\n", m.decodeTokensPerSecond()));
out.append(String.format(Locale.ROOT, " <charsPerToken>%.2f</charsPerToken>\n", m.charsPerToken()));
out.append("</calibration>\n");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -87,6 +92,64 @@ public void renderXml_rendersOnePasteBlockPerModelInOrder() {
assertThat(report.renderXml(), is(expected));
}

@Test
public void renderXml_endsEveryLineWithLineFeedOnACrLfPlatform() throws IOException, InterruptedException {
// String.format's %n is the platform line separator, fixed when the JVM starts, so only a JVM
// whose separator is CRLF (Windows) shows a mixed block; on Linux this test starts one.
final List<String> command = new ArrayList<>();
command.add(Paths.get(System.getProperty("java.home"), "bin", "java").toString());
if (!"\r\n".equals(System.lineSeparator())) {
command.add("-Dline.separator=\r\n");
}
command.add("-cp");
command.add(System.getProperty("java.class.path"));
command.add(RenderXmlInThisJvm.class.getName());
final Process process = new ProcessBuilder(command).start();
final byte[] stdout = readAll(process.getInputStream());
final byte[] stderr = readAll(process.getErrorStream());
final int exit = process.waitFor();

assertThat(new String(stderr, StandardCharsets.UTF_8), exit, is(0));
final String xml = new String(stdout, StandardCharsets.UTF_8);
assertThat(xml, not(containsString("\r")));
assertThat(xml, is(RenderXmlInThisJvm.EXPECTED));
}

private static byte[] readAll(final InputStream in) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final byte[] buffer = new byte[8192];
for (int n; (n = in.read(buffer)) != -1; ) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}

/** Renders one block in a JVM started with a CRLF line separator; fails when it is not one. */
static final class RenderXmlInThisJvm {

static final String EXPECTED = "<!-- calibration for aiDefinition 'model-a' (this machine) -->\n"
+ "<calibration>\n"
+ " <prefillTokensPerSecond>1000.5</prefillTokensPerSecond>\n"
+ " <decodeTokensPerSecond>200.3</decodeTokensPerSecond>\n"
+ " <charsPerToken>4.57</charsPerToken>\n"
+ "</calibration>\n";

private RenderXmlInThisJvm() {}

public static void main(final String[] args) throws IOException {
if (!"\r\n".equals(System.lineSeparator())) {
// Without the CRLF separator the test would pass vacuously; the exception exits the
// child with a failure status and its message reaches the parent on stderr.
throw new IllegalStateException("the line separator of this JVM is not CRLF");
}
final CalibrationReport report =
new CalibrationReport(Collections.singletonList(new CalibrationReport.ModelMeasurement(
"model-a", new AiCalibrationMeasurement(1.234d, 1000.5d, 200.3d, 4.57d, 900.0d, 128))));
System.out.write(report.renderXml().getBytes(StandardCharsets.UTF_8));
System.out.flush();
}
}

@Test
public void toString_containsModelKey() {
final CalibrationReport report = new CalibrationReport(Arrays.asList(new CalibrationReport.ModelMeasurement(
Expand Down
Loading