fix(core): NAT entries expire exactly at their age, not at Java's next one-second check

Java's GatewayFirmware.checkNAT and SwitchFirmware.checkSAT look every
second from the start, so an entry goes up to a second late. The engine
expires both exactly at their age: better than Java where Java only
samples, as long as saved files stay compatible (decided 01.10.2026).
The switch did so already; its departure is now named in the code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 14:06:55 +00:00
co-authored by Claude Opus 5.5
parent 088b62469f
commit 739deafbf4
4 changed files with 22 additions and 19 deletions
+4 -4
View File
@@ -2221,15 +2221,15 @@ describe('Home router NAT', () => {
expect(engine.bindUdpSocket(gatewayId, { localPort: entry.port })).toBeUndefined();
});
it("drops an entry at the first of Java's checks, each second from the start, when it is 300 s times the delay factor old; answers refresh it", () => {
it('drops an entry when it is 300 s times the delay factor old, not at the next of Java\'s checks each second; answers refresh it', () => {
const engine = home({ speed: 100 });
udpOut(engine);
// At 100 %, the factor is 1: 300 s. The entry came at 15 ms (three cables of 5 ms); it is gone at the check at 301 s.
// At 100 %, the factor is 1: 300 s. The entry came at 15 ms (three cables of 5 ms); it is gone at 300.015 s (Java: at its check at 301 s).
const [entry] = engine.natEntries(gatewayId) as [NatEntry];
expect(entry.updatedAtMilliseconds).toBe(15);
engine.handle({ type: 'advance', toMilliseconds: 300_999 });
engine.handle({ type: 'advance', toMilliseconds: 300_014 });
expect(engine.natEntries(gatewayId)).toHaveLength(1);
engine.handle({ type: 'advance', toMilliseconds: 301_000 });
engine.handle({ type: 'advance', toMilliseconds: 300_015 });
expect(engine.natEntries(gatewayId)).toHaveLength(0);
// Another, now refreshed by an answer, and not by what goes out.