feat(core): a cable carries one frame after the other, as in Java

Java's SimplexVerbindung sleeps a cable's delay with the port's buffer
locked: frames on one cable leave one after the other, and a frame shows
in the packet log when it leaves. The engine now queues a frame in the
output buffer until the one before has arrived (ethernetLinkDeparture).
Swift sends a cable's frames at once; the option swiftCables keeps that for
the Swift comparison, which goes on checking everything else trace by
trace.

With the queue, the Java comparisons match within 120 ms (was 200); a
state of the TCP stories within 250 ms, where the engine's calls block
one after the other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 16:37:45 +00:00
co-authored by Claude Opus 5.5
parent cec0a92f95
commit efc7c440f6
7 changed files with 153 additions and 15 deletions
+5 -4
View File
@@ -11,9 +11,6 @@
// client draws differs (Java's random, the engine's seed); it is compared as
// "client". Times count from the client's SYN.
//
// The engine's calls block on its virtual clock one after the other, where
// Java's server answers in a thread of its own: the server's answer starts
// when the client's send returns, one cable's delay later than in Java.
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
@@ -26,6 +23,10 @@ import type { Scenario } from './scenario.js';
const scenarioDirectory = join(dirname(fileURLToPath(import.meta.url)), 'scenarios');
const STATE_UNSEEN_MILLISECONDS = 20;
// The engine's calls block one after the other: in exchange, the server's
// answer starts when the client's send returns, and the client closes when
// the server's send returns — two cables' delay each, later than in Java.
const STATE_TOLERANCE_MILLISECONDS = 250;
const SERVER = '00000000-0000-0000-0000-000000000101';
const CLIENT = '00000000-0000-0000-0000-000000000102';
const OTHER_CLIENT = '00000000-0000-0000-0000-000000000103';
@@ -109,7 +110,7 @@ function expectSameStates(label: string, actual: [number, string][], expected: [
for (const [time, state] of expected) {
const index = actual.findIndex(([, each], candidate) => candidate >= next && each === state);
expect(index, `${label}: ${state} (Java at ${time} ms)`).toBeGreaterThanOrEqual(0);
expect(Math.abs(actual[index]![0] - time), `${label}: time of ${state}`).toBeLessThanOrEqual(GAP_TOLERANCE_MILLISECONDS);
expect(Math.abs(actual[index]![0] - time), `${label}: time of ${state}`).toBeLessThanOrEqual(STATE_TOLERANCE_MILLISECONDS);
matched.add(index);
next = index + 1;
}