diff --git a/spigot/src/test/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilterPipelineTest.java b/spigot/src/test/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilterPipelineTest.java
new file mode 100644
index 00000000..1613aa74
--- /dev/null
+++ b/spigot/src/test/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilterPipelineTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2021-2022 Minekube. https://minekube.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author Minekube
+ * @link https://github.com/minekube/connect-java
+ */
+
+package com.minekube.connect.addon.data;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import com.minekube.connect.config.ConnectConfig;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.embedded.EmbeddedChannel;
+import java.lang.reflect.Method;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Optional;
+import net.minecraft.network.chat.LastSeenMessages;
+import net.minecraft.network.chat.MessageSignature;
+import net.minecraft.network.protocol.game.ServerboundChatAckPacket;
+import net.minecraft.network.protocol.game.ServerboundChatPacket;
+import net.minecraft.network.protocol.game.ServerboundChatSessionUpdatePacket;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * The customer's shape, asserted at the layer that actually ends the tunneled session.
+ *
+ *
A Connect-tunneled Spigot player runs on the injected local channel, whose pipeline is
+ * {@code decoder -> connect_data_handler -> connect_chat_session_filter -> } ({@code SpigotDataAddon.onInject}). Chat arrives after spawn, so a handler that
+ * cannot handle a 26.3 packet shape never fails the login: it throws with the player already in
+ * play, the vanilla network manager disconnects them ({@code lost connection: Internal Exception:
+ * ...}), and the injected channel close ends the tunnel - the ~1 s post-spawn teardown the
+ * connector's lines then report as {@code Connect tunneled player X disconnected}.
+ *
+ *
On connect-spigot 0.15.14 the filter resolved {@code ServerboundChatPacket}'s constructor from
+ * hard-coded parameter types, while Minecraft had moved the signature component to
+ * {@code Optional}. Every plain post-spawn chat packet from a 26.3 client
+ * therefore threw inside the pipeline; reproduced live against Paper 26.3 through the Connect edge,
+ * that closed the session 1.23 s after spawn with
+ * {@code NoSuchMethodException: ServerboundChatPacket.(String,Instant,long,MessageSignature,
+ * LastSeenMessages$Update)} (fixed by connect-java#170, released in 0.15.15).
+ *
+ *
These tests guard the pipeline, not just the rewrite: the post-spawn packet sequence must
+ * leave the session open, on 26.3 and unchanged for the older packet shapes.
+ */
+class SpigotChatSessionPacketFilterPipelineTest {
+ private final List