ServerlessIRCd Docs

Docs home

ADR-007: Deterministic ports for time and ID generation

Date: 2025-01-15 (Phase 1) Status: Accepted Supersedes: — Superseded by: —

Context

IRC protocol behaviour is time-sensitive: idle/PING timers, WHOIS signon time, server-time tags (ISO-8601 timestamps on every message), SASL nonce generation, chathistory message IDs. A traditional ircd calls Date.now() and crypto.randomUUID() directly in handlers. This makes tests non-deterministic: the same input produces different output on every run, depending on when the test executed.

Non-determinism is fatal for the parametrized contract suite (TICKET-032), which runs identical scenarios across in-memory, CF, and AWS runtimes. If a reducer embeds Date.now(), the expected @time= tag changes every millisecond and the assertion cannot be written.

Decision

Time and ID generation are injected ports, not global calls:

interface Clock {
  now(): number;  // epoch milliseconds
}

interface IdFactory {
  nonce(): string;     // unique message ID for message-tags/chathistory
  traceId(): string;   // per-request trace ID for observability
}

Both are passed through Ctx to every reducer. Reducers read ctx.clock.now() and ctx.ids.nonce() — never Date.now() or Math.random().

Concrete implementations:

Consequences

Positive:

Negative:

References