Version: 1.1.0 | Status: Sprint 12 A1–A7 implementiert; A8 Stufe 1 nachgewiesen, Stufen 2–4 offen | Verantwortungsbereich: Lead Multiplayer Engineer / Betrieb | Sprint: 12
Der Relay-Server (tools/Nova.RelayServer, Prozess nova-relay) verbindet
genau zwei Clients für ein deterministisches Lockstep-Match. Er simuliert
nicht. Er prüft und verteilt Command-Records, schließt Ticks über den
TickComplete-Barrier, vergleicht State-Hashes und kann den bestätigten
Transportstrom als NOVAREC2 aufzeichnen.
Die Architekturentscheidung steht in
D-089, das Protokoll in
RelayProtocol.cs
und der Serverkern in
RelayServerCore.cs.
Dieses Dokument ist das Runbook für den mit
relay-publish.yml und
deploy.sh gelieferten
Betriebspfad.
- Der aktuelle Transport ist rohes TCP, zuverlässig und geordnet. Es gibt keinen implementierten WebSocket-, nginx-, TLS- oder UDP-Pfad.
- Das Match-Token wird erst im
Helloals anwendungsseitiger Berechtigungswert geprüft; es ist weder Transportverschlüsselung noch Schutz vor Socket-/Slot-Erschöpfung. Den TCP-Port nur bewusst und möglichst auf die beiden Quelladressen begrenzt öffnen. - Der Relay simuliert nicht und bestätigt kein Match-Ergebnis. Es gibt in
dieser Stufe kein
MatchComplete, Reconnect, Matchmaking, Lobby, Observer oder Host-Migration. TickCompleteist ausschließlich ein Transport-/Barrier-Frame. Er erreicht die Command-Ingress nicht und ist weder Command, Replay-Ergebnis noch State-Hash-Ereignis.- Ein Relay-Prozess bedient nacheinander 1v1-Sessions mit exakt zwei Slots. Das ist kein allgemeiner Mehrmatch-Host.
- Secrets liegen ausschließlich in der manuell provisionierten Datei
/etc/hashkrieg-relay.env. Unit, Beispielkonfiguration, Artefakt und Deploymentcode enthalten kein echtes Token.
Frames sind little-endian und längenpräfigiert:
[u32 payloadBytes][u8 type][payload]
Der feste Header hat fünf Byte; der Payload ist auf 8 MiB begrenzt.
| Frame | Richtung | Bedeutung |
|---|---|---|
Hello |
Client → Server | Protokollversion und Match-Token |
Offer |
Server → Client | Slot, aktive Slots, Seed, Input-Delay und Definitionshash |
Fingerprint |
Client → Server | kanonischer Match-Fingerprint |
InitialSnapshot |
Client → Server | kanonischer Initialzustand |
Start |
Server → Client | beide Startbeweise stimmen; Match darf laufen |
Reject |
Server → Client | Handshake-/Protokollablehnung |
CommandRecord |
Client → Relay → anderer Client | ein kanonischer Gameplay-Command |
TickComplete |
Client → Relay → anderer Client | Slot, Zieltick und exakte Record-Anzahl für den Barrier; kein Echo an den Absender |
StateHash |
Client → Server | State-Hash am 50-Tick-Checkpoint |
Desync |
Server → Client | die beiden Checkpoint-Hashes weichen ab |
PeerLost |
Server → Client | Peer verloren; die Session endet |
Ping / Pong |
Client → Server / Server → Client | RTT-Probe und Echo |
Vor Start bindet der Beweis beide Peers an denselben Seed, Input-Delay,
Definitionshash, vollständigen Fingerprint und byteidentischen
Initialsnapshot. Das Netzprofil verwendet standardmäßig drei Ticks Delay; der
erlaubte Bereich ist 1 bis 60. Der kanonische lokale Defaultwert ist ein Tick;
MatchConfig/Loopback erlauben ebenfalls 1 bis 60.
Der Absender markiert seine lokale Completion unmittelbar selbst. Der Relay
prüft den eingehenden TickComplete gegen seine exakt akzeptierte Record-Anzahl
und leitet ihn nur an den anderen Client weiter. Bei aktivierter Aufzeichnung
persistiert er den Tick erst in NOVAREC2, wenn er beide Slot-Completions
bestätigt hat. Dieser Persistenz-Barrier ist nicht mit einem Roundtrip-Gate für
die eigene Client-Completion zu verwechseln.
Der Relay akzeptiert seit Sprint 14.5 (D-093)
zwei Token-Arten im selben 64-Bit-Feld des Hello. Das Protokoll bleibt bei
Version 1; ein Lobby-Token ist auf dem Draht nur ein weiterer u64-Wert. Der
Codec liegt in
LobbyToken.cs, die
Lobby-Edge-Function (Deno) muss ihn bitgenau spiegeln.
Statisches Token (NOVA_MATCH_TOKEN): wie bisher vom Administrator
provisioniert, unbegrenzt wiederverwendbar; der Match-Seed ist konfiguriert
(NOVA_RELAY_SEED) oder wird je Match neu gewürfelt. Bleibt Pflicht und ist
der Direktweg für Tests und Betrieb ohne Lobby.
Lobby-Token: kurzlebig, von der externen Lobby (Supabase) pro Match
gemintet. Lobby und Relay teilen ausschließlich das statische HMAC-Secret
NOVA_RELAY_TOKEN_SECRET per Konfiguration — es gibt bewusst keinen neuen
Kanal zwischen ihnen. Layout der 64 Bit:
- Bits 63..44: 20-bit Ablauf-Bucket =
floor((unixMs − 2026-01-01T00:00:00Z) / 300000), also 5-Minuten-Scheiben. - Bits 43..32: 12-bit Match-Id (Zufallszahl der Lobby).
- Bits 31..0: 32-bit Tag = erste 4 Bytes von
HMAC-SHA256(secret, ASCII "NOVA-LOBBY-TOKEN-V1" ‖ bucket als u32 big-endian ‖ matchId als u16 big-endian).
Semantik im Relay:
- Gültig ist ein Lobby-Token, wenn der Tag stimmt (Fixed-Time-Vergleich) und
sein Bucket im Fenster
[aktuell − 5, aktuell]liegt — ein 30-Minuten-Fenster. - Single-Use: Der erste Peer bindet das Token an das Match; der zweite Peer muss exakt dasselbe Token vorzeigen. Nach dem Match-Reset ist das Token verbraucht und nie wieder verwendbar — auch wenn das Match nie gestartet ist. Verbrauchte Einträge werden gepurgt, sobald ihr Bucket das Gültigkeitsfenster verlassen hat (solche Tokens können nie wieder gültig werden).
- Seed: Der Offer-Seed eines Lobby-Matches wird aus dem Token abgeleitet —
HMAC-SHA256(secret, ASCII "NOVA-LOBBY-SEED-V1" ‖ token als u64 big-endian), erste 8 Bytes, Ergebnis| 1, damit er nie die Zufallsseed-Konvention 0 berührt. Beide Clients erhalten so denselben Seed, ohne dass er je übertragen oder verhandelt wird. - Ablehnungen nennen weiterhin nur „wrong match code"; Token und Token-Bestandteile erscheinen weder in Logs noch in Fehlertexten.
- Ein gebundenes Token wird erst beim Match-Reset freigegeben beziehungsweise verbraucht: Verschwindet der wartende Peer vor Matchbeginn, bleibt das Token bis zum Reset gebunden und andere Lobby-Matches warten.
Grenzen dieses Vertrags:
- Der 32-bit Tag ist ein Zulassungs-MAC, keine Transportverschlüsselung; Online-Raten scheitert praktisch an den zwei Slots und dem 5-Sekunden-Handshake-Timeout je Verbindung.
- Der 20-bit Bucket läuft nach 2^20 Scheiben (≈ 9,97 Jahre) über, frühestens 2036; das Minting danach ist nicht Teil dieses Vertrags.
- Die 12-bit Match-Id kann innerhalb eines Fensters kollidieren: gleiche Bucket- und Id-Werte ergeben dasselbe Token. Die Lobby muss Ids so ziehen, dass sie innerhalb eines 30-Minuten-Fensters nicht doppelt vergibt.
Der Workflow veröffentlicht kein Single-File-Binary, sondern einen
self-contained linux-x64-Publish-Baum. Das Bundle enthält:
app/ vollständiger self-contained Publish-Baum
deploy/deploy.sh Bootstrap, Deploy und Rollback
deploy/hashkrieg-relay.service
deploy/hashkrieg-relay.env.example
BUILD_INFO Commit-SHA, SDK 8.0.318, Runtime linux-x64
SHA256SUMS exaktes inneres Dateimanifest
Zu jedem Archiv
hashkrieg-relay-<40-stellige-commit-sha>-linux-x64.tar.gz gehört die äußere
Prüfsumme mit Suffix .sha256. Auf dem Server gilt:
/opt/hashkrieg-relay/releases/<commit-sha>/ unveränderliches Release
/opt/hashkrieg-relay/current atomarer Link auf das aktive Release
/opt/hashkrieg-relay/previous atomarer Link auf den Rollback-Kandidaten
/opt/hashkrieg-relay/current/app/nova-relay systemd-Executable
/etc/hashkrieg-relay.env manuell, root:root, Modus 0600
/etc/hashkrieg-relay.env.example absichtlich ungültiges Beispiel
/var/lib/hashkrieg-relay/ systemd-StateDirectory
deploy.sh akzeptiert nur Linux x86_64, muss als root laufen und serialisiert
Operationen mit flock. Release-Verzeichnisse sind nach der 40-stelligen
Commit-SHA benannt, root-owned und werden nie überschrieben.
Der Prozess akzeptiert keine Kommandozeilenargumente. Jede Konfiguration kommt aus der Umgebung:
| Variable | Pflicht | Default | Gültiger Wert |
|---|---|---|---|
NOVA_MATCH_TOKEN |
ja | – | exakt 16 unpräfixierte Hexzeichen, nicht 0000000000000000; wird nie geloggt |
NOVA_RELAY_BIND |
nein | 127.0.0.1 |
numerische IPv4- oder IPv6-Adresse; kein Hostname |
NOVA_RELAY_PORT |
nein | 47777 |
dezimal 1024–65535 |
NOVA_RELAY_SLOT_COUNT |
nein | 2 |
exakt 2 |
NOVA_INPUT_DELAY_TICKS |
nein | 3 |
dezimal 1–60 |
NOVA_RECORD_DIR |
nein | Aufzeichnung aus | absoluter Pfad, nicht / |
NOVA_RELAY_SEED |
nein | neuer, zufälliger Seed | wenn gesetzt: exakt 16 unpräfixierte Hexzeichen, nicht null |
NOVA_RELAY_TOKEN_SECRET |
nein | nur statisches Token | wenn gesetzt: exakt 64 unpräfixierte Hexzeichen (32 Bytes); wird nie geloggt |
Ist NOVA_RECORD_DIR gesetzt, prüft der Prozess vor dem Listener-Start, ob er
das Verzeichnis erstellen, eine Probe schreiben, auf den Datenträger flushen
und wieder löschen kann. Ein Fehler ist ein Konfigurationsfehler; es gibt
keinen stillen Betrieb ohne die verlangte Aufzeichnung.
Exitcodes:
| Code | Bedeutung | systemd-Folge |
|---|---|---|
0 |
geordnetes Ende nach SIGINT/SIGTERM |
kein Fehlerrestart |
1 |
Setup-, Laufzeit- oder Shutdownfehler | Restart=on-failure |
78 |
ungültige Umgebung oder unerlaubtes Argument | durch RestartPreventExitStatus=78 kein Restart-Loop |
Der implementierte Spielstart besitzt noch keine Ingame-Lobby und kein Feld
für einen Matchcode. Relay-Modus wird pro Unity-Prozess ausschließlich durch
NOVA_RELAY_HOST aktiviert. Beide Prozesse müssen vor ihrem Start dieselben
erreichbaren Host-/Portwerte und dasselbe serverseitig provisionierte Token
erhalten; Platzhalter ersetzen, kein echtes Token in Skripte oder das Repo
schreiben:
export NOVA_RELAY_HOST='<relay-host-or-ip>'
export NOVA_RELAY_PORT='47777'
export NOVA_MATCH_TOKEN='<same-16-hex-token>'
# Unity-Player beziehungsweise Editor-Prozess aus dieser Umgebung startenNOVA_RELAY_PORT ist auf Clientseite bei gesetztem Host Pflicht und muss 1 bis
65.535 sein. NOVA_MATCH_TOKEN muss exakt 16 unpräfixierte Hexzeichen lang und
ungleich null sein; sein Wert muss mit der Serverumgebung übereinstimmen. Der
Relay weist den beiden erfolgreich verbundenen Prozessen automatisch Slot 0
und Slot 1 zu.
Fehlt NOVA_RELAY_HOST oder ist es leer, startet der bestehende lokale
Mensch-gegen-KI-Pfad. Ist der Host dagegen gesetzt und Port oder Token fehlen
beziehungsweise ungültig, meldet MatchBootstrap einen sichtbaren
Netzwerkstartfehler und fällt nicht still auf ein lokales Match zurück.
Das Bootstrap installiert Benutzer, Gruppe, Verzeichnisse, Unit und die
Beispieldatei. Es erstellt, liest oder überschreibt nicht die Live-Datei
/etc/hashkrieg-relay.env.
Die drei Deploy-Dateien zuerst aus einem geprüften Checkout derselben Ziel-Commit-SHA auf den Server übertragen. Beispiel vom Administrationsrechner:
ssh root@relay-host \
'install -d -o root -g root -m 0700 /root/hashkrieg-relay-bootstrap'
scp tools/Nova.RelayServer/deploy/deploy.sh \
tools/Nova.RelayServer/deploy/hashkrieg-relay.service \
tools/Nova.RelayServer/deploy/hashkrieg-relay.env.example \
root@relay-host:/root/hashkrieg-relay-bootstrap/Dann auf dem Server:
cd /root/hashkrieg-relay-bootstrap
chmod 0755 deploy.sh
./deploy.sh bootstrap
systemctl is-enabled hashkrieg-relay.servicebootstrap legt den unprivilegierten Systembenutzer und die Gruppe
novarelay an, installiert die Unit nach
/etc/systemd/system/hashkrieg-relay.service, kopiert nur das ungültige
Beispiel nach /etc/hashkrieg-relay.env.example, führt daemon-reload aus
und aktiviert den Dienst für den Boot. Ohne Live-Umgebung wird noch kein
Release gestartet.
Die Datei wird ausschließlich durch einen Administrator angelegt. Der
Create-only-Aufruf mit Dateimodus x bricht ab, wenn der Pfad bereits
existiert, und überschreibt deshalb niemals ein vorhandenes Token:
umask 077
python3 -c 'open("/etc/hashkrieg-relay.env", "x").close()'
chown root:root /etc/hashkrieg-relay.env
chmod 0600 /etc/hashkrieg-relay.env
sudoedit /etc/hashkrieg-relay.env
stat -c '%U:%G %a %n' /etc/hashkrieg-relay.envExistiert die Live-Datei bereits, den Create-only-Aufruf nicht wiederholen;
nur Besitz und Modus prüfen beziehungsweise korrigieren und danach mit
sudoedit bearbeiten. Kein Bootstrap- oder Deploy-Schritt ersetzt ihren
Inhalt.
Inhalt für einen bewusst öffentlich gebundenen Einzelhost; den Token-Platzhalter vor dem ersten Deploy durch einen zufälligen 16-stelligen Hexwert ersetzen:
NOVA_MATCH_TOKEN=REPLACE_WITH_16_HEX_DIGITS
NOVA_RELAY_BIND=0.0.0.0
NOVA_RELAY_PORT=47777
NOVA_RELAY_SLOT_COUNT=2
NOVA_INPUT_DELAY_TICKS=3
NOVA_RECORD_DIR=/var/lib/hashkrieg-relay/recordsNOVA_RELAY_SEED für normale Matches weglassen. Ein gesetzter Seed ist für
reproduzierbare Testläufe gedacht und muss ebenfalls exakt 16 Hexzeichen und
ungleich null sein. Die Live-Datei niemals committen, als Terminalausgabe
anzeigen oder zusammen mit einem Support-Log übertragen.
Eine Formprüfung des Tokens ohne Ausgabe seines Werts:
awk -F= '
$1 == "NOVA_MATCH_TOKEN" {
seen++
if (NF != 2 || $2 !~ /^[[:xdigit:]]{16}$/ || $2 ~ /^0+$/) bad = 1
}
END { exit (seen == 1 && !bad) ? 0 : 1 }
' /etc/hashkrieg-relay.envDer Workflow läuft auf Pull Requests, main-Pushes und manuell. Er verwendet
exakt .NET SDK 8.0.318, führt die kanonischen Tests aus, publiziert den
self-contained Baum, prüft fehlenden Token/unerlaubte Argumente und einen
geordneten SIGTERM, baut beide Prüfsummen und lädt ein Bundle nur bei einem
main-Push oder einem manuellen Lauf auf main hoch. Er verwendet weder SSH
noch Deployment-Secrets und rollt nichts auf einen Server aus.
Beispiel auf dem Administrationsrechner:
release_sha=<40-stellige-kleinbuchstaben-commit-sha>
run_id=<github-actions-run-id>
artifact_name="hashkrieg-relay-${release_sha}-linux-x64"
gh run download "${run_id}" --name "${artifact_name}" --dir relay-artifact
(
cd relay-artifact
sha256sum -c "${artifact_name}.tar.gz.sha256"
)gh run download authentisiert den Ursprung des Actions-Artefakts; die
äußere SHA-Datei erkennt Übertragungsänderungen. Das Deploy prüft danach
erneut die äußere Prüfsumme und zusätzlich das exakte innere Manifest.
Archiv und SHA-Datei in ein root-only Eingangsverzeichnis auf dem Server übertragen:
install -d -o root -g root -m 0700 /root/hashkrieg-relay-incomingVom Administrationsrechner:
scp relay-artifact/hashkrieg-relay-<sha>-linux-x64.tar.gz \
relay-artifact/hashkrieg-relay-<sha>-linux-x64.tar.gz.sha256 \
root@relay-host:/root/hashkrieg-relay-incoming/Erstes Deploy mit dem geprüften Bootstrap-Skript, spätere Deploys wahlweise mit der geprüften Skriptversion der Ziel-Commit-SHA:
/root/hashkrieg-relay-bootstrap/deploy.sh deploy \
/root/hashkrieg-relay-incoming/hashkrieg-relay-<sha>-linux-x64.tar.gz \
/root/hashkrieg-relay-incoming/hashkrieg-relay-<sha>-linux-x64.tar.gz.sha256Der Ablauf ist fail-closed:
- Live-Umgebung muss regulär, root-owned und ohne Gruppen-/Weltrechte sein.
- Archiv und äußere SHA-Datei werden ohne Symlink-Folgen in ein root-only Staging kopiert; nur diese stabilen Bytes werden weiterverarbeitet.
- Äußere SHA-256, Tar-Struktur und inneres
SHA256SUMSwerden geprüft. Traversal, Symlinks, Hardlinks, Spezialdateien, Duplikate, unerwartete Dateien und Größenüberschreitungen werden abgelehnt. BUILD_INFOmuss exakt Commit-SHA, SDK8.0.318undlinux-x64binden.- Der vollständige Baum wird root-owned normalisiert und unter
/opt/hashkrieg-relay/releases/<sha>unveränderlich abgelegt. - Unit sowie
current/previouswechseln atomar. Das Deployment startet den Dienst und wartet auf Readiness. - Bei fehlgeschlagener Aktivierung werden Unit und Links auf den vorigen Stand zurückgesetzt; auch der wiederhergestellte Dienst muss Readiness bestehen.
Readiness bedeutet: innerhalb von 30 Sekunden fünf aufeinanderfolgende
active-Beobachtungen mit derselben gültigen systemd-InvocationID und einem
[Relay] ready on ...-Eintrag genau dieser Invocation. Inaktivität, ein
Invocation-Wechsel, ein fehlender Ready-Eintrag oder failed setzt die Serie
zurück beziehungsweise bricht ab.
systemctl status hashkrieg-relay.service --no-pager
systemctl show hashkrieg-relay.service \
-p ActiveState -p SubState -p Result -p ExecMainStatus -p InvocationID
journalctl -u hashkrieg-relay.service -n 200 --no-pager -o cat
ss -ltnp '( sport = :47777 )'Der Prozess loggt Bind-Adresse, Port, Slotzahl, Input-Delay und ob Recording aktiv ist, aber nie das Match-Token. Keine Befehle verwenden, die die EnvironmentFile oder den Prozess-Environment-Inhalt ausgeben.
Die Unit läuft als novarelay:novarelay, verwendet
EnvironmentFile=/etc/hashkrieg-relay.env,
ExecStart=/opt/hashkrieg-relay/current/app/nova-relay, journald,
StateDirectory=hashkrieg-relay, UMask=0077, SIGTERM mit 15 Sekunden
Timeout, Restart=on-failure und RestartPreventExitStatus=78. Sie entfernt
Capabilities und aktiviert die im Repository stehenden systemd-Härtungen.
Ein Rollback setzt den vorherigen unveränderlichen Release-Baum atomar als
current, verschiebt den bisherigen aktiven Baum nach previous, installiert
dessen Unit und wendet denselben Readiness-Vertrag wie beim Deploy an:
/opt/hashkrieg-relay/current/deploy/deploy.sh rollbackFehlt einer der beiden Links oder zeigen beide auf dasselbe Release, wird abgebrochen. Scheitert der Rollback-Kandidat an Readiness, stellt das Skript den zuvor aktiven Stand wieder her und prüft auch dessen Readiness. Die Live-Umgebung wird weder kopiert noch verändert.
Der Dienst braucht einen eingehenden TCP-Port, standardmäßig 47777. Die
Host- und gegebenenfalls Provider-Firewall müssen übereinstimmen. Wo feste
öffentliche Spieleradressen bekannt sind, nur diese freigeben.
Ubuntu/Debian mit UFW, je Spieleradresse wiederholen:
ufw allow proto tcp from 198.51.100.10 to any port 47777 \
comment 'Hashkrieg relay player 1'
ufw status numberedRHEL/Fedora mit firewalld, je Spieleradresse wiederholen:
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.10/32" port port="47777" protocol="tcp" accept'
firewall-cmd --reload
firewall-cmd --list-rich-rules198.51.100.10 ist eine Dokumentationsadresse und muss ersetzt werden. Bei
dynamischen Spieleradressen ist eine allgemeine Freigabe (47777/tcp) eine
bewusste Risikoentscheidung. Das Match-Token ist nur eine nachgelagerte
Anwendungsprüfung im Hello, keine frühe Verbindungszulassung. Die
Zweiergrenze ist ausschließlich eine Kapazitätsgrenze und schützt nicht vor
DoS: Der Server reserviert Slots bereits beim TCP-Accept vor einem gültigen
Hello, sodass zwei unauthentisierte Verbindungen beide Slots bis zum
Handshake-Timeout vorübergehend blockieren können. Deshalb ist die enge
Quelladress-Firewall die wichtigste Betriebsgrenze. Persistenzsyntax und
Regelreihenfolge unterscheiden sich je Distribution und Cloud-Anbieter. Es
gibt keinen nginx-/WebSocket-Ersatz für den rohen TCP-Port.
Konfiguration oder Argumentvertrag ist ungültig. systemd startet den Prozess
absichtlich nicht in einer Schleife neu.
stat -c '%U:%G %a %n' /etc/hashkrieg-relay.env
systemctl show hashkrieg-relay.service -p Result -p ExecMainStatus
journalctl -u hashkrieg-relay.service -n 50 --no-pager -o catPrüfen: Token exakt 16 Hexzeichen und nicht null, numerische Bind-Adresse,
Port 1024–65535, Slotzahl exakt 2, Delay 1–60, Seedformat und absoluter
Record-Pfad ungleich /. Keine zusätzlichen Argumente an nova-relay geben.
Listener-, Polling- oder Shutdownfehler. Häufige Ursachen sind ein belegter Port oder eine Laufzeitstörung. Listener und letzte Logs prüfen; danach erst gezielt neu starten:
ss -ltnp '( sport = :47777 )'
systemctl reset-failed hashkrieg-relay.service
systemctl restart hashkrieg-relay.serviceNOVA_RECORD_DIR muss unter dem StateDirectory für novarelay erstell- und
schreibbar sein. Die Unit erzeugt /var/lib/hashkrieg-relay mit Modus 0700.
Besitz und Rechte prüfen, nicht durch eine Weltfreigabe umgehen:
stat -c '%U:%G %a %n' /var/lib/hashkrieg-relay
namei -l /var/lib/hashkrieg-relay/recordsDer Prozess muss fünf stabile Beobachtungen derselben Invocation bestehen.
Eine kurze ready-Meldung vor einem Crash reicht nicht. Invocation, Status und
Journal gemeinsam prüfen:
systemctl show hashkrieg-relay.service -p InvocationID -p ActiveState -p Result
journalctl -u hashkrieg-relay.service --no-pager -o catDas Deploy stellt den vorigen Zustand automatisch wieder her. Nicht manuell
current umbiegen; sonst gehen die transaktionalen Invarianten verloren.
Archive und .sha256 müssen zusammengehören. Der Tar darf ausschließlich den
festen Bundle-Inhalt tragen, und das innere Manifest muss jede Datei außer
SHA256SUMS exakt einmal abdecken. Ein bereits vorhandenes Release derselben
Commit-SHA ist absichtlich unveränderlich und wird nicht überschrieben.
NOVA_RELAY_BIND=127.0.0.1 ist der sichere Default und nur lokal erreichbar.
Für einen externen Host bewusst auf eine öffentliche numerische Adresse oder
0.0.0.0 binden, Dienst neu starten und danach Listener, Host-Firewall und
Provider-Firewall prüfen. Kein Port-Forwarding am Client ist erforderlich;
beide Clients bauen ausgehende TCP-Verbindungen auf.
Stand 2026-08-07 lief lokal
dotnet test tools/Nova.SimRunner.Tests/Nova.SimRunner.Tests.csproj -c Release --no-restore --nologo
mit 547/547 grünen Tests, 0 übersprungen, in 11 s; darin lief der 10.023-Tick-
Soak erneut grün. Die vollständige LockstepNetworkTests-Klasse war zusätzlich
62/62 grün (3 s), der gezielte Fail-Closed-/Delay-/Timing-Pass 23/23 grün
(156 ms).
dotnet build tools/Nova.RelayServer/Nova.RelayServer.csproj -c Release --no-restore --nologo
endete mit 0 Warnungen und 0 Fehlern; auch Konfigurations-, Argument- und
geordnete Signal-Smokes wurden ausgeführt. Ein offline aus lokalem Cache
erzeugter self-contained
linux-x64-Baum hatte 186 Dateien; äußere und 190 innere Prüfsummen sowie der
gehärtete Extraktor wurden geprüft. A8 Stufe 1 lief mit zwei echten TCP-
Clients über den Relay bis Tick 10.023 und reproduzierte den Live-Endhash im
NOVAREC2-Playback; Checkpoints lagen alle 50 Ticks vor.
Nicht ausgeführt wurden ein Linux-ELF-Start, ein echtes systemd-/root-Deploy,
ein Live-Lauf des GitHub-Workflows, eine VPS-Installation und A8 Stufen 2–4
(zwei Unity-Fenster, LAN, VPS). Der Unity-EditMode-Versuch scheiterte vor den
Tests am Lizenzhandshake 505 Unsupported protocol version 1.18.1; es gibt
daher kein Test-XML und keinen grünen Unity-Nachweis. Der Netzwerkpfad ist
technisch verdrahtet, aber noch nicht durch eine gespielte Netzwerkpartie
abgenommen.
- Workflow auf dem neuen PR ausführen und das erzeugte Actions-Artefakt prüfen.
- A8 Stufe 2 mit zwei Unity-Fenstern über Loopback spielen.
- Danach LAN (Stufe 3) und erst nach ausdrücklicher Freigabe Bootstrap, Firewall und Deploy auf dem VPS durchführen.
- Die vollständige VPS-Partie bis zum Ergebnisbildschirm als A8 Stufe 4 protokollieren.
| Version | Datum | Änderung | Autor |
|---|---|---|---|
| 0.1.0 | 2026-08-07 | Vorläufiges Server-/Protokollblatt für A1–A5 | Agent (Umsetzung) |
| 1.0.0 | 2026-08-07 | D-089-Vertrag, vollständigen Artifact-/systemd-/Deploy-/Rollback-Pfad und ehrlichen A8-Nachweisstand dokumentiert | Technical Writer |
| 1.1.0 | 2026-08-09 | Kurzlebige Lobby-Match-Tokens (D-093, Sprint 14.5) | Agent (Umsetzung) |