@@ -36,7 +36,7 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
3636** Parallel:** yes — can run alongside TASK-003-002
3737
3838** Acceptance Criteria:**
39- - [ ] ` Http3ConnectionConfig ` record created in ` src/TurboHTTP/Protocol/Http3/ ` :
39+ - [x ] ` Http3ConnectionConfig ` record created in ` src/TurboHTTP/Protocol/Http3/ ` :
4040 ``` csharp
4141 public sealed record Http3ConnectionConfig (
4242 int MaxFieldSectionSize = 65536 ,
@@ -46,7 +46,7 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
4646 int MaxReconnectAttempts = 3 ,
4747 bool AllowServerPush = false );
4848 ```
49- - [ ] ` IHttp3StageOperations ` interface created in ` src/TurboHTTP/Protocol/Http3/ ` :
49+ - [x ] ` IHttp3StageOperations ` interface created in ` src/TurboHTTP/Protocol/Http3/ ` :
5050 ``` csharp
5151 public interface IHttp3StageOperations
5252 {
@@ -56,8 +56,8 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
5656 void OnReconnectFailed ();
5757 }
5858 ```
59- - [ ] Follows ` IHttp2StageOperations ` naming and callback semantics exactly
60- - [ ] Typecheck passes
59+ - [x ] Follows ` IHttp2StageOperations ` naming and callback semantics exactly
60+ - [x ] Typecheck passes
6161
6262** Files to create:**
6363- ` src/TurboHTTP/Protocol/Http3/Http3ConnectionConfig.cs `
@@ -77,16 +77,16 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
7777** Parallel:** yes — can run alongside TASK-003-001
7878
7979** Acceptance Criteria:**
80- - [ ] ` Http3StreamTracker ` class created in ` src/TurboHTTP/Protocol/Http3/ `
81- - [ ] Tracks client-initiated bidirectional stream IDs (0, 4, 8, 12, ... — incremented by 4 per RFC 9114 §6.1)
82- - [ ] ` AllocateStreamId() ` returns next ID and advances counter by 4
83- - [ ] ` CanOpenStream() ` checks against concurrency limit
84- - [ ] ` OnStreamOpened(long streamId) ` / ` OnStreamClosed(long streamId) ` manage active set
85- - [ ] ` Reset() ` clears state for reconnection
86- - [ ] ` ActiveStreamCount ` , ` MaxConcurrentStreams ` , ` NextStreamId ` properties
87- - [ ] Uses ` long ` for stream IDs (QUIC uses 62-bit variable-length integers, unlike HTTP/2's 31-bit)
88- - [ ] Unit tests in ` src/TurboHTTP.Tests/Http3/Connection/Http3StreamTrackerSpec.cs `
89- - [ ] Typecheck passes
80+ - [x ] ` Http3StreamTracker ` class created in ` src/TurboHTTP/Protocol/Http3/ `
81+ - [x ] Tracks client-initiated bidirectional stream IDs (0, 4, 8, 12, ... — incremented by 4 per RFC 9114 §6.1)
82+ - [x ] ` AllocateStreamId() ` returns next ID and advances counter by 4
83+ - [x ] ` CanOpenStream() ` checks against concurrency limit
84+ - [x ] ` OnStreamOpened(long streamId) ` / ` OnStreamClosed(long streamId) ` manage active set
85+ - [x ] ` Reset() ` clears state for reconnection
86+ - [x ] ` ActiveStreamCount ` , ` MaxConcurrentStreams ` , ` NextStreamId ` properties
87+ - [x ] Uses ` long ` for stream IDs (QUIC uses 62-bit variable-length integers, unlike HTTP/2's 31-bit)
88+ - [x ] Unit tests in ` src/TurboHTTP.Tests/Http3/Connection/Http3StreamTrackerSpec.cs `
89+ - [x ] Typecheck passes
9090
9191** Files to create:**
9292- ` src/TurboHTTP/Protocol/Http3/Http3StreamTracker.cs `
@@ -107,28 +107,28 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
107107** Model:** opus
108108
109109** Acceptance Criteria:**
110- - [ ] ` Http3StateMachine ` class created in ` src/TurboHTTP/Protocol/Http3/StateMachine.cs `
111- - [ ] Constructor takes ` Http3ConnectionConfig ` + ` IHttp3StageOperations `
112- - [ ] Owns ` Http3StreamTracker ` , ` ConnectionState ` (moved from Http30ConnectionStage inner class)
113- - [ ] ` ConnectionState ` class moved from ` Http30ConnectionStage ` to ` StateMachine ` (or extracted to own file)
114- - [ ] Key methods:
110+ - [x ] ` Http3StateMachine ` class created in ` src/TurboHTTP/Protocol/Http3/StateMachine.cs `
111+ - [x ] Constructor takes ` Http3ConnectionConfig ` + ` IHttp3StageOperations `
112+ - [x ] Owns ` Http3StreamTracker ` , ` ConnectionState ` (moved from Http30ConnectionStage inner class)
113+ - [x ] ` ConnectionState ` class moved from ` Http30ConnectionStage ` to ` StateMachine ` (or extracted to own file)
114+ - [x ] Key methods:
115115 - ` ProcessFrame(Http3Frame frame) ` — handles SETTINGS, GOAWAY, PUSH_PROMISE, CANCEL_PUSH, MAX_PUSH_ID, forwards DATA/HEADERS via callback
116116 - ` SendRequest(Http3Frame frame) ` — validates GOAWAY not received, tracks stream open, enqueues outbound
117117 - ` bool CanAcceptRequest ` — no GOAWAY + not reconnecting + concurrency budget
118118 - ` bool IsReconnecting ` / ` int ReconnectBufferCount `
119119 - ` OnConnectionLost() ` — enters reconnect state, buffers in-flight requests
120120 - ` OnConnectionRestored() ` — replays buffered requests via callback
121121 - ` OnReconnectFailed() ` — signals callback after max attempts exhausted
122- - [ ] All existing ` Http30ConnectionStage.Logic ` protocol logic migrated to StateMachine
123- - [ ] Unit tests in ` src/TurboHTTP.Tests/Http3/Connection/Http3StateMachineSpec.cs ` covering:
122+ - [x ] All existing ` Http30ConnectionStage.Logic ` protocol logic migrated to StateMachine
123+ - [x ] Unit tests in ` src/TurboHTTP.Tests/Http3/Connection/Http3StateMachineSpec.cs ` covering:
124124 - SETTINGS processing
125125 - GOAWAY handling (single, decreasing stream IDs, invalid IDs)
126126 - Push promise rejection (AllowServerPush = false)
127127 - Push promise acceptance (AllowServerPush = true)
128128 - Stream lifecycle (open/close tracking)
129129 - Idle timeout expiry
130130 - Reconnection enter/replay/fail
131- - [ ] Typecheck passes
131+ - [x ] Typecheck passes
132132
133133** Files to create:**
134134- ` src/TurboHTTP/Protocol/Http3/StateMachine.cs `
@@ -150,20 +150,20 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
150150** Model:** opus
151151
152152** Acceptance Criteria:**
153- - [ ] ` Http30ConnectionStage ` constructor takes ` Http3ConnectionConfig ` (not just ` TimeSpan idleTimeout ` )
154- - [ ] ` Logic ` class implements ` IHttp3StageOperations `
155- - [ ] ` Logic ` creates ` Http3StateMachine ` in constructor
156- - [ ] All frame handling delegated: ` HandleServerFrame ` → ` _sm.ProcessFrame(frame) ` , outbound → ` _sm.SendRequest(frame) `
157- - [ ] ` ConnectionState ` inner class removed (now lives in StateMachine)
158- - [ ] ` IHttp3StageOperations ` callbacks translate to Akka operations:
153+ - [x ] ` Http30ConnectionStage ` constructor takes ` Http3ConnectionConfig ` (not just ` TimeSpan idleTimeout ` )
154+ - [x ] ` Logic ` class implements ` IHttp3StageOperations `
155+ - [x ] ` Logic ` creates ` Http3StateMachine ` in constructor
156+ - [x ] All frame handling delegated: ` HandleServerFrame ` → ` _sm.ProcessFrame(frame) ` , outbound → ` _sm.SendRequest(frame) `
157+ - [x ] ` ConnectionState ` inner class removed (now lives in StateMachine)
158+ - [x ] ` IHttp3StageOperations ` callbacks translate to Akka operations:
159159 - ` OnResponse ` → ` Push(_outApp, frame) `
160160 - ` OnOutbound ` → ` EnqueueOutbound(frame) `
161161 - ` OnWarning ` → ` Log.Warning(...) `
162162 - ` OnReconnectFailed ` → ` FailStage(...) `
163- - [ ] ` Http30Engine ` updated to pass ` Http3ConnectionConfig ` to stage
164- - [ ] All existing stream tests in ` src/TurboHTTP.StreamTests/Http3/ ` pass unchanged
165- - [ ] All existing stream tests in ` src/TurboHTTP.StreamTests/Http3/Connection/ ` pass unchanged
166- - [ ] Typecheck passes
163+ - [x ] ` Http30Engine ` updated to pass ` Http3ConnectionConfig ` to stage
164+ - [x ] All existing stream tests in ` src/TurboHTTP.StreamTests/Http3/ ` pass unchanged
165+ - [x ] All existing stream tests in ` src/TurboHTTP.StreamTests/Http3/Connection/ ` pass unchanged
166+ - [x ] Typecheck passes
167167
168168** Files to modify:**
169169- ` src/TurboHTTP/Streams/Stages/Decoding/Http30ConnectionStage.cs ` (major refactor)
@@ -183,19 +183,19 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
183183** Parallel:** no
184184
185185** Acceptance Criteria:**
186- - [ ] ` Http3StateMachine.OnConnectionLost() ` enters reconnect state:
186+ - [x ] ` Http3StateMachine.OnConnectionLost() ` enters reconnect state:
187187 - Sets ` _reconnecting = true `
188188 - Buffers pending outbound frames in ` _reconnectBuffer `
189189 - Increments ` _reconnectAttempts `
190- - [ ] ` Http3StateMachine.OnConnectionRestored() ` replays buffer:
190+ - [x ] ` Http3StateMachine.OnConnectionRestored() ` replays buffer:
191191 - Resets stream tracker (` _tracker.Reset() ` )
192192 - Replays buffered frames via ` _ops.OnOutbound() `
193193 - Clears ` _reconnecting ` and ` _reconnectBuffer `
194- - [ ] After ` MaxReconnectAttempts ` exhausted → ` _ops.OnReconnectFailed() `
195- - [ ] ` Http30ConnectionStage.Logic ` handles upstream finish during reconnect (fails stage)
196- - [ ] Unit tests in StateMachine spec: reconnect enter, replay, max attempts
197- - [ ] Stream test: ` Http30ConnectionStageReconnectSpec.cs ` — simulates transport failure and recovery
198- - [ ] Typecheck passes
194+ - [x ] After ` MaxReconnectAttempts ` exhausted → ` _ops.OnReconnectFailed() `
195+ - [x ] ` Http30ConnectionStage.Logic ` handles upstream finish during reconnect (fails stage)
196+ - [x ] Unit tests in StateMachine spec: reconnect enter, replay, max attempts
197+ - [x ] Stream test: ` Http30ConnectionStageReconnectSpec.cs ` — simulates transport failure and recovery
198+ - [x ] Typecheck passes
199199
200200** Files to modify:**
201201- ` src/TurboHTTP/Protocol/Http3/StateMachine.cs ` (add reconnect fields + methods)
@@ -219,13 +219,13 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
219219** Parallel:** yes — can run alongside TASK-003-007, TASK-003-008, TASK-003-009
220220
221221** Acceptance Criteria:**
222- - [ ] ` Http3ConnectionConfig.AllowServerPush ` (already added in TASK-003-001) flows through to StateMachine
223- - [ ] When ` AllowServerPush = false ` : PUSH_PROMISE triggers CANCEL_PUSH frame via ` _ops.OnOutbound() `
224- - [ ] When ` AllowServerPush = true ` : PUSH_PROMISE is forwarded to app layer
225- - [ ] ` MAX_PUSH_ID ` frame sent with appropriate value based on config
226- - [ ] Unit test: push rejected when disabled, accepted when enabled
227- - [ ] Existing ` Http30PushRejectionSpec ` stream test still passes
228- - [ ] Typecheck passes
222+ - [x ] ` Http3ConnectionConfig.AllowServerPush ` (already added in TASK-003-001) flows through to StateMachine
223+ - [x ] When ` AllowServerPush = false ` : PUSH_PROMISE triggers CANCEL_PUSH frame via ` _ops.OnOutbound() `
224+ - [x ] When ` AllowServerPush = true ` : PUSH_PROMISE is forwarded to app layer
225+ - [x ] ` MAX_PUSH_ID ` frame sent with appropriate value based on config
226+ - [x ] Unit test: push rejected when disabled, accepted when enabled
227+ - [x ] Existing ` Http30PushRejectionSpec ` stream test still passes
228+ - [x ] Typecheck passes
229229
230230** Files to modify:**
231231- ` src/TurboHTTP/Protocol/Http3/StateMachine.cs ` (ProcessFrame PUSH_PROMISE branch)
@@ -241,15 +241,15 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
241241** Parallel:** yes — can run alongside TASK-003-006, TASK-003-008, TASK-003-009
242242
243243** Acceptance Criteria:**
244- - [ ] ` Http3Options.AllowEarlyData ` property added (bool, default false)
245- - [ ] ` Http3ConnectionConfig ` includes ` AllowEarlyData `
246- - [ ] ` Http30Request2FrameStage ` checks if request method is idempotent (GET, HEAD, OPTIONS, TRACE, DELETE)
247- - [ ] Idempotent requests tagged with ` EarlyData = true ` when ` AllowEarlyData ` is enabled
248- - [ ] ` QuicTransportStateMachine ` / ` QuicClientProvider ` uses ` QuicStream.CanWrite ` for early data
249- - [ ] On 0-RTT rejection: request re-sent after full handshake
250- - [ ] Unit test: idempotent request marked for early data
251- - [ ] Unit test: non-idempotent request blocked from early data
252- - [ ] Typecheck passes
244+ - [x ] ` Http3Options.AllowEarlyData ` property added (bool, default false)
245+ - [x ] ` Http3ConnectionConfig ` includes ` AllowEarlyData `
246+ - [x ] ` Http30Request2FrameStage ` checks if request method is idempotent (GET, HEAD, OPTIONS, TRACE, DELETE)
247+ - [x ] Idempotent requests tagged with ` EarlyData = true ` when ` AllowEarlyData ` is enabled
248+ - [x ] ` QuicTransportStateMachine ` / ` QuicClientProvider ` uses ` QuicStream.CanWrite ` for early data
249+ - [x ] On 0-RTT rejection: request re-sent after full handshake
250+ - [x ] Unit test: idempotent request marked for early data
251+ - [x ] Unit test: non-idempotent request blocked from early data
252+ - [x ] Typecheck passes
253253
254254** Files to modify:**
255255- ` src/TurboHTTP/Http3Options.cs `
@@ -268,13 +268,13 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
268268** Parallel:** yes — can run alongside TASK-003-006, TASK-003-007, TASK-003-009
269269
270270** Acceptance Criteria:**
271- - [ ] ` Http3Options.AllowConnectionMigration ` property added (bool, default true)
272- - [ ] ` QuicTransportStateMachine ` detects address changes on the QUIC connection
273- - [ ] When migration detected and allowed: connection continues transparently
274- - [ ] When migration detected and disallowed: connection closed, new connection established (leverages reconnect from TASK-003-005)
275- - [ ] Unit test: migration allowed continues seamlessly
276- - [ ] Unit test: migration disallowed triggers reconnect
277- - [ ] Typecheck passes
271+ - [x ] ` Http3Options.AllowConnectionMigration ` property added (bool, default true)
272+ - [x ] ` QuicTransportStateMachine ` detects address changes on the QUIC connection
273+ - [x ] When migration detected and allowed: connection continues transparently
274+ - [x ] When migration detected and disallowed: connection closed, new connection established (leverages reconnect from TASK-003-005)
275+ - [x ] Unit test: migration allowed continues seamlessly
276+ - [x ] Unit test: migration disallowed triggers reconnect
277+ - [x ] Typecheck passes
278278
279279** Files to modify:**
280280- ` src/TurboHTTP/Http3Options.cs `
@@ -293,14 +293,14 @@ HTTP/2's connection handling follows a clean architecture: `StateMachine` (all p
293293** Model:** opus
294294
295295** Acceptance Criteria:**
296- - [ ] ` AltSvcCache ` class created: per-host cache of Alt-Svc directives with TTL
297- - [ ] Alt-Svc header parsed from HTTP/1.1 and HTTP/2 responses (RFC 7838)
298- - [ ] ` AltSvcEntry ` record: protocol, host, port, maxAge, persist flag
299- - [ ] Integration point in ` ProtocolCoreBuilder ` or ` RequestEnricher ` : check cache before version selection
300- - [ ] If HTTP/3 advertised and QUIC available: upgrade endpoint version to 3.0
301- - [ ] ` Http3Options.EnableAltSvcDiscovery ` property (bool, default false — opt-in)
302- - [ ] Unit tests: Alt-Svc header parsing, cache TTL expiry, upgrade decision
303- - [ ] Typecheck passes
296+ - [x ] ` AltSvcCache ` class created: per-host cache of Alt-Svc directives with TTL
297+ - [x ] Alt-Svc header parsed from HTTP/1.1 and HTTP/2 responses (RFC 7838)
298+ - [x ] ` AltSvcEntry ` record: protocol, host, port, maxAge, persist flag
299+ - [x ] Integration point in ` ProtocolCoreBuilder ` or ` RequestEnricher ` : check cache before version selection
300+ - [x ] If HTTP/3 advertised and QUIC available: upgrade endpoint version to 3.0
301+ - [x ] ` Http3Options.EnableAltSvcDiscovery ` property (bool, default false — opt-in)
302+ - [x ] Unit tests: Alt-Svc header parsing, cache TTL expiry, upgrade decision
303+ - [x ] Typecheck passes
304304
305305** Files to create:**
306306- ` src/TurboHTTP/Protocol/AltSvc/AltSvcCache.cs `
0 commit comments