ocaml http/1, http/2 and websocket client and server library
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

bd sync: 2026-01-03 22:12:32

+191 -131
+1 -1
.beads/.local_version
··· 1 - 0.29.0 1 + 0.43.0
+190 -130
.beads/issues.jsonl
··· 1 - {"id":"hcs-0ro","title":"Implement WebSocket frame types and parsing","description":"Implement WebSocket wire format in hcs-core/ws_frame.ml:\n\n```ocaml\ntype frame =\n | Text of string\n | Binary of Cstruct.t\n | Ping of Cstruct.t\n | Pong of Cstruct.t\n | Close of int option * string option\n\ntype parse_result =\n | Complete of frame * int (* frame and bytes consumed *)\n | Incomplete of int (* need more bytes *)\n | Error of string\n\nval parse_frame : Cstruct.t -\u003e parse_result\nval serialize_frame : ?mask:bool -\u003e frame -\u003e Cstruct.t\n\n(* Handshake *)\nval make_handshake_request : Uri.t -\u003e ?protocols:string list -\u003e Headers.t -\u003e request\nval validate_handshake_response : response -\u003e (string option, string) result (* selected protocol *)\nval make_handshake_response : request -\u003e ?protocol:string -\u003e (response, string) result\n```\n\nPure parsing/serialization.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:32.864373772+01:00","updated_at":"2025-12-29T16:00:43.877842667+01:00","closed_at":"2025-12-29T16:00:43.877842667+01:00","dependencies":[{"issue_id":"hcs-0ro","depends_on_id":"hcs-lhr","type":"parent-child","created_at":"2025-12-29T14:34:52.111489961+01:00","created_by":"gdiazlo"}]} 2 - {"id":"hcs-0y4","title":"Implement compression middleware with gzip and zstd support","description":"","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T18:44:00.161388436+01:00","updated_at":"2026-01-01T18:53:17.947904901+01:00","closed_at":"2026-01-01T18:53:17.947904901+01:00"} 3 - {"id":"hcs-0zq","title":"Testing Infrastructure and Compliance","description":"Set up testing infrastructure including unit tests, integration tests, and HTTP compliance test suites for both client and server implementations.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:35:43.905080385+01:00","updated_at":"2025-12-29T17:57:31.987947689+01:00","closed_at":"2025-12-29T17:57:31.987947689+01:00","dependencies":[{"issue_id":"hcs-0zq","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:35:55.080432801+01:00","created_by":"gdiazlo"}]} 4 - {"id":"hcs-15v","title":"Run tests and fix any issues","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:16:47.827724667+01:00","updated_at":"2026-01-01T22:22:18.249274206+01:00","closed_at":"2026-01-01T22:22:18.249274206+01:00","dependencies":[{"issue_id":"hcs-15v","depends_on_id":"hcs-g40","type":"blocks","created_at":"2026-01-01T22:17:06.229519632+01:00","created_by":"gdiazlo"}]} 5 - {"id":"hcs-1h7","title":"Create Go WebSocket benchmark server","description":"Go server using gorilla/websocket or nhooyr.io/websocket. Same interface as HCS: accept connections, keep alive, report count.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T09:59:59.144195314+01:00","updated_at":"2025-12-30T10:08:50.856707182+01:00","closed_at":"2025-12-30T10:08:50.856707182+01:00","dependencies":[{"issue_id":"hcs-1h7","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:30.601603816+01:00","created_by":"gdiazlo"}]} 1 + {"id":"hcs-0bi","title":"docs: Create docs/ folder structure and README","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T00:44:13.323975386+01:00","updated_at":"2026-01-03T00:47:16.216273256+01:00","closed_at":"2026-01-03T00:47:16.216273256+01:00"} 2 + {"id":"hcs-0ro","title":"Implement WebSocket frame types and parsing","description":"Implement WebSocket wire format in hcs-core/ws_frame.ml:\n\n```ocaml\ntype frame =\n | Text of string\n | Binary of Cstruct.t\n | Ping of Cstruct.t\n | Pong of Cstruct.t\n | Close of int option * string option\n\ntype parse_result =\n | Complete of frame * int (* frame and bytes consumed *)\n | Incomplete of int (* need more bytes *)\n | Error of string\n\nval parse_frame : Cstruct.t -\u003e parse_result\nval serialize_frame : ?mask:bool -\u003e frame -\u003e Cstruct.t\n\n(* Handshake *)\nval make_handshake_request : Uri.t -\u003e ?protocols:string list -\u003e Headers.t -\u003e request\nval validate_handshake_response : response -\u003e (string option, string) result (* selected protocol *)\nval make_handshake_response : request -\u003e ?protocol:string -\u003e (response, string) result\n```\n\nPure parsing/serialization.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:32.864373772+01:00","updated_at":"2025-12-29T16:00:43.877842667+01:00","closed_at":"2025-12-29T16:00:43.877842667+01:00","dependencies":[{"issue_id":"hcs-0ro","depends_on_id":"hcs-lhr","type":"parent-child","created_at":"2025-12-29T14:34:52.111489961+01:00","created_by":"gdiazlo","metadata":"{}"}]} 3 + {"id":"hcs-0y4","title":"Implement compression middleware with gzip and zstd support","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T18:44:00.161388436+01:00","updated_at":"2026-01-01T18:53:17.947904901+01:00","closed_at":"2026-01-01T18:53:17.947904901+01:00"} 4 + {"id":"hcs-0zq","title":"Testing Infrastructure and Compliance","description":"Set up testing infrastructure including unit tests, integration tests, and HTTP compliance test suites for both client and server implementations.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:35:43.905080385+01:00","updated_at":"2025-12-29T17:57:31.987947689+01:00","closed_at":"2025-12-29T17:57:31.987947689+01:00","dependencies":[{"issue_id":"hcs-0zq","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:35:55.080432801+01:00","created_by":"gdiazlo","metadata":"{}"}]} 5 + {"id":"hcs-15v","title":"Run tests and fix any issues","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:16:47.827724667+01:00","updated_at":"2026-01-01T22:22:18.249274206+01:00","closed_at":"2026-01-01T22:22:18.249274206+01:00","dependencies":[{"issue_id":"hcs-15v","depends_on_id":"hcs-g40","type":"blocks","created_at":"2026-01-01T22:17:06.229519632+01:00","created_by":"gdiazlo","metadata":"{}"}]} 6 + {"id":"hcs-1h7","title":"Create Go WebSocket benchmark server","description":"Go server using gorilla/websocket or nhooyr.io/websocket. Same interface as HCS: accept connections, keep alive, report count.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T09:59:59.144195314+01:00","updated_at":"2025-12-30T10:08:50.856707182+01:00","closed_at":"2025-12-30T10:08:50.856707182+01:00","dependencies":[{"issue_id":"hcs-1h7","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:30.601603816+01:00","created_by":"gdiazlo","metadata":"{}"}]} 7 + {"id":"hcs-1lvl","title":"[Epic] v0.2.0: Router pipelines + per-route plugs (Phoenix-style)","description":"Refactor to support plugs at multiple layers like Phoenix:\n\n1. **Endpoint**: Global plugs (static files, request_id, session) - ALL requests\n2. **Router Pipelines**: Groups of plugs applied to route scopes (browser vs api)\n3. **Per-route plugs**: Individual routes with their own middleware\n\nAlso fix Endpoint to not duplicate Server config.\n\nThis is a breaking change.","status":"open","priority":1,"issue_type":"epic","created_at":"2026-01-03T20:59:19.284234549+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:10:45.319880674+01:00"} 6 8 {"id":"hcs-1op","title":"Web framework building blocks","description":"Implement 5 core features to make HCS a minimal but complete web framework: Sessions, Tokens, Content Negotiation, Endpoint, and PubSub/Channels. Focus on minimal allocations, functional composition, and simplicity over feature parity with Phoenix.","status":"closed","priority":1,"issue_type":"epic","created_at":"2026-01-01T20:46:34.289608444+01:00","updated_at":"2026-01-01T21:36:15.141649231+01:00","closed_at":"2026-01-01T21:36:15.141649231+01:00"} 7 - {"id":"hcs-1uy","title":"HTTP/2 Specific Features","description":"Implement H2 module with server push, stream priority, and HTTP/2 detection.","status":"closed","priority":3,"issue_type":"epic","created_at":"2025-12-29T14:25:37.55760677+01:00","updated_at":"2025-12-29T17:40:54.000014455+01:00","closed_at":"2025-12-29T17:40:54.000014455+01:00","dependencies":[{"issue_id":"hcs-1uy","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:20.914923161+01:00","created_by":"gdiazlo"}]} 8 - {"id":"hcs-1vt","title":"Implement HTTP/2 server (Eio)","description":"Implement HTTP/2 server for Eio in hcs-eio/h2_server.ml:\n\n```ocaml\nval handle_connection :\n flow:Eio.Flow.two_way -\u003e\n clock:Eio.Time.clock -\u003e\n config:Server.config -\u003e\n handler:(request -\u003e (response, error) result) -\u003e\n unit\n```\n\nFeatures:\n- HPACK header compression\n- Stream multiplexing (concurrent requests)\n- Flow control\n- Server push support\n- GOAWAY for graceful shutdown\n- Priority handling\n\nDepends on hpack package.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:33:25.282940788+01:00","updated_at":"2025-12-29T16:00:42.340368477+01:00","closed_at":"2025-12-29T16:00:42.340368477+01:00","dependencies":[{"issue_id":"hcs-1vt","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:42.729783837+01:00","created_by":"gdiazlo"}]} 9 - {"id":"hcs-23f","title":"Implement synchronous Stream module (core)","description":"Implement the synchronous Stream module in hcs-core/stream.ml:\n\nProducers:\n- empty, singleton, of_list, of_seq\n- unfold : ('s -\u003e ('a * 's) option) -\u003e 's -\u003e 'a t\n\nTransformers:\n- map, filter, filter_map\n- take, drop, chunks\n\nConsumers:\n- fold, iter, drain\n- to_string (for Cstruct.t streams)\n\nCombinators:\n- concat, zip\n\nThis is the pure, synchronous implementation. Runtime-specific async streams will wrap this.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:28:01.435958367+01:00","updated_at":"2025-12-29T14:51:05.189865738+01:00","closed_at":"2025-12-29T14:51:05.189865738+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-23f","depends_on_id":"hcs-czm","type":"parent-child","created_at":"2025-12-29T14:28:16.036236675+01:00","created_by":"gdiazlo"}]} 10 - {"id":"hcs-240","title":"LAS: Main entry point (las.ml)","description":"Endpoint with plug pipeline: Logger, Compress, Session, Csrf, Rate_limit. Start server with WebSocket support.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:42:02.46889176+01:00","updated_at":"2026-01-02T10:28:15.478431398+01:00","closed_at":"2026-01-02T10:28:15.478431398+01:00","dependencies":[{"issue_id":"hcs-240","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:58.522626786+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-240","depends_on_id":"hcs-nwb","type":"blocks","created_at":"2026-01-01T23:43:48.930728118+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-240","depends_on_id":"hcs-q4v","type":"blocks","created_at":"2026-01-01T23:43:53.974339722+01:00","created_by":"gdiazlo"}]} 11 - {"id":"hcs-2ca","title":"Implement Eio TLS integration","description":"Implement TLS context creation for Eio runtime in hcs-eio/tls.ml:\n\n- Convert Tls_config.client to Tls.Config.client\n- Convert Tls_config.server to Tls.Config.server \n- Load system certificates using ca-certs\n- Handle ALPN negotiation for HTTP/2\n- Wrap Eio flows with TLS\n\nDepends on tls-eio, ca-certs, x509 packages.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:30:34.350512358+01:00","updated_at":"2025-12-29T15:24:43.224163622+01:00","closed_at":"2025-12-29T15:24:43.224163622+01:00","dependencies":[{"issue_id":"hcs-2ca","depends_on_id":"hcs-y9w","type":"parent-child","created_at":"2025-12-29T14:30:47.016262637+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-2ca","depends_on_id":"hcs-cyb","type":"blocks","created_at":"2025-12-29T14:30:47.870432453+01:00","created_by":"gdiazlo"}]} 12 - {"id":"hcs-2ie","title":"Router Implementation","description":"Implement Path DSL for type-safe extraction and Router module with trie-based route lookup, scoping, and middleware support.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:30.896190732+01:00","updated_at":"2025-12-29T15:41:48.160193387+01:00","closed_at":"2025-12-29T15:41:48.160193387+01:00","dependencies":[{"issue_id":"hcs-2ie","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:15.462426699+01:00","created_by":"gdiazlo"}]} 13 - {"id":"hcs-320","title":"Create benchmark client for load generation","description":"Create a benchmark client (bin/hcs_bench_client.ml) that generates load and measures performance:\n- Configurable concurrency (number of parallel connections)\n- Configurable duration or request count\n- Support for HTTP/1.1 and HTTP/2\n- Measures: requests/second, latency (min/max/avg/p50/p99), errors\n- Reports results in human-readable and JSON formats\n\nShould use Eio fibers for concurrent requests.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T18:03:53.28432088+01:00","updated_at":"2025-12-29T18:15:36.842283087+01:00","closed_at":"2025-12-29T18:15:36.842283087+01:00","dependencies":[{"issue_id":"hcs-320","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:20.175343889+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-320","depends_on_id":"hcs-40d","type":"blocks","created_at":"2025-12-29T18:04:35.617524274+01:00","created_by":"gdiazlo"}]} 14 - {"id":"hcs-3dn","title":"Create HCS-based benchmark client for testing all servers","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T22:21:41.677601767+01:00","updated_at":"2025-12-30T22:31:12.664814017+01:00","closed_at":"2025-12-30T22:31:12.664814017+01:00"} 15 - {"id":"hcs-3ww","title":"Middleware System","description":"Implement Middleware module with composition, logging, security (CORS, auth), rate limiting, compression, caching, and static files.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:34.907454455+01:00","updated_at":"2025-12-29T17:40:52.182994384+01:00","closed_at":"2025-12-29T17:40:52.182994384+01:00","dependencies":[{"issue_id":"hcs-3ww","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:19.080036903+01:00","created_by":"gdiazlo"}]} 16 - {"id":"hcs-40d","title":"Implement latency histogram and percentile calculations","description":"Create a statistics module (lib/bench_stats.ml or in the benchmark binary) for accurate latency measurements:\n- HDR histogram or simple sorted array for percentiles\n- Calculate min, max, mean, stddev\n- Calculate p50, p90, p95, p99, p99.9 percentiles\n- Track request count, error count, bytes transferred\n- Support for merging stats from multiple workers","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T18:03:57.696657065+01:00","updated_at":"2025-12-29T18:15:29.902324683+01:00","closed_at":"2025-12-29T18:15:29.902324683+01:00","dependencies":[{"issue_id":"hcs-40d","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:22.619809769+01:00","created_by":"gdiazlo"}]} 17 - {"id":"hcs-42q","title":"Implement runtime-parameterized async Stream","description":"Design async stream interface that works with both Eio and Lwt:\n\n```ocaml\nmodule type ASYNC_STREAM = sig\n type 'a io\n type 'a t\n \n val from_flow : ... -\u003e Cstruct.t t\n val from_file : ... -\u003e Cstruct.t t\n val to_sink : ... -\u003e Cstruct.t t -\u003e unit io\nend\n\nmodule Make_stream (R : RUNTIME) : ASYNC_STREAM with type 'a io = 'a R.t\n```\n\nThe Eio implementation uses Eio.Flow, the future Lwt version will use Lwt_io.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:28:05.317935403+01:00","updated_at":"2025-12-29T17:08:13.483830721+01:00","closed_at":"2025-12-29T17:08:13.483830721+01:00","labels":["architecture","core"],"dependencies":[{"issue_id":"hcs-42q","depends_on_id":"hcs-czm","type":"parent-child","created_at":"2025-12-29T14:28:16.763534695+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-42q","depends_on_id":"hcs-23f","type":"blocks","created_at":"2025-12-29T14:28:17.658557754+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-42q","depends_on_id":"hcs-6bi","type":"blocks","created_at":"2025-12-29T14:28:18.52508237+01:00","created_by":"gdiazlo"}]} 18 - {"id":"hcs-4w8","title":"Create benchmark server with configurable endpoints","description":"Create a dedicated benchmark server (bin/hcs_bench_server.ml) with endpoints optimized for benchmarking:\n- GET /ping - minimal response (measures raw throughput)\n- GET /bytes/:n - returns n bytes (measures payload handling)\n- POST /echo - echoes request body (measures request body parsing)\n- GET /delay/:ms - adds artificial delay (measures concurrency)\n- GET /headers/:n - returns n headers (measures header handling)\n\nServer should support both HTTP/1.1 and HTTP/2, with configurable port and worker count.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T18:03:49.541780606+01:00","updated_at":"2025-12-29T18:15:27.763639409+01:00","closed_at":"2025-12-29T18:15:27.763639409+01:00","dependencies":[{"issue_id":"hcs-4w8","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:17.563056726+01:00","created_by":"gdiazlo"}]} 19 - {"id":"hcs-505","title":"Add HTTP/2 benchmark endpoints and comparison scripts","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T00:14:16.705365323+01:00","updated_at":"2025-12-30T00:28:18.304877441+01:00","closed_at":"2025-12-30T00:28:18.304877441+01:00"} 20 - {"id":"hcs-52s","title":"Remove mirage-crypto-rng-eio/unix from tests","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-02T00:23:50.329970611+01:00","updated_at":"2026-01-02T10:16:17.801891715+01:00","closed_at":"2026-01-02T10:16:17.801891715+01:00"} 21 - {"id":"hcs-56z","title":"Implement HTTP/1.1 server parser/serializer","description":"Implement HTTP/1.1 server wire format in hcs-core/h1.ml (extend existing):\n\n```ocaml\n(* Request parsing *)\ntype request_parse_result =\n | Complete of request * int (* request and bytes consumed *)\n | Incomplete of int (* need more bytes *)\n | Error of string\n\nval parse_request_head : Cstruct.t -\u003e request_parse_result\n\n(* Response serialization *)\nval serialize_response : response -\u003e Cstruct.t\nval serialize_response_head : response -\u003e Cstruct.t\n```\n\nPure parsing, zero-copy with Cstruct views.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:19.050407222+01:00","updated_at":"2025-12-29T14:56:39.076056919+01:00","closed_at":"2025-12-29T14:56:39.076056919+01:00","dependencies":[{"issue_id":"hcs-56z","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:41.058840522+01:00","created_by":"gdiazlo"}]} 22 - {"id":"hcs-5eu","title":"Implement Log module","description":"Implement logging in hcs-core/log.ml:\n\n```ocaml\ntype level = Debug | Info | Warn | Error\n\ntype event =\n | Request_start of { id: string; meth: method_; uri: Uri.t }\n | Request_end of { id: string; status: status; duration_ms: float }\n | Connection_open of { host: string; port: int }\n | Connection_close of { host: string; port: int; reason: string }\n | Connection_reuse of { host: string; port: int }\n | Tls_handshake of { host: string; protocol: string }\n | Retry of { id: string; attempt: int; reason: error }\n | Error of { id: string; error: error }\n\ntype logger = level -\u003e event -\u003e unit\n\n(* Built-in loggers *)\nval null : logger\nval stderr : ?min_level:level -\u003e unit -\u003e logger\nval custom : (level -\u003e string -\u003e unit) -\u003e logger\n\n(* Format event as string *)\nval event_to_string : event -\u003e string\nval level_to_string : level -\u003e string\n```\n\nPure OCaml, no runtime dependency.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:30:26.138649492+01:00","updated_at":"2025-12-29T17:06:37.134220488+01:00","closed_at":"2025-12-29T17:06:37.134220488+01:00","dependencies":[{"issue_id":"hcs-5eu","depends_on_id":"hcs-fgd","type":"parent-child","created_at":"2025-12-29T14:30:45.51204607+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-5eu","depends_on_id":"hcs-gmb","type":"blocks","created_at":"2025-12-29T14:30:48.61530863+01:00","created_by":"gdiazlo"}]} 9 + {"id":"hcs-1uy","title":"HTTP/2 Specific Features","description":"Implement H2 module with server push, stream priority, and HTTP/2 detection.","status":"closed","priority":3,"issue_type":"epic","created_at":"2025-12-29T14:25:37.55760677+01:00","updated_at":"2025-12-29T17:40:54.000014455+01:00","closed_at":"2025-12-29T17:40:54.000014455+01:00","dependencies":[{"issue_id":"hcs-1uy","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:20.914923161+01:00","created_by":"gdiazlo","metadata":"{}"}]} 10 + {"id":"hcs-1v2c","title":"Implement: Add health_check as optional Plug","description":"Consider making health_check a proper Plug instead of baked-in behavior:\n- Create Plug.Health module (or keep inline)\n- Allow custom health check paths/responses\n- Make it opt-in rather than opt-out\n\nThis is optional but cleaner design.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T20:59:39.352248651+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:11:08.141670622+01:00","closed_at":"2026-01-03T21:11:08.141670622+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-1v2c","depends_on_id":"hcs-pcri","type":"blocks","created_at":"2026-01-03T21:00:12.788719112+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-1v2c","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:19.523428797+01:00","created_by":"gdiazlo"}]} 11 + {"id":"hcs-1vt","title":"Implement HTTP/2 server (Eio)","description":"Implement HTTP/2 server for Eio in hcs-eio/h2_server.ml:\n\n```ocaml\nval handle_connection :\n flow:Eio.Flow.two_way -\u003e\n clock:Eio.Time.clock -\u003e\n config:Server.config -\u003e\n handler:(request -\u003e (response, error) result) -\u003e\n unit\n```\n\nFeatures:\n- HPACK header compression\n- Stream multiplexing (concurrent requests)\n- Flow control\n- Server push support\n- GOAWAY for graceful shutdown\n- Priority handling\n\nDepends on hpack package.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:33:25.282940788+01:00","updated_at":"2025-12-29T16:00:42.340368477+01:00","closed_at":"2025-12-29T16:00:42.340368477+01:00","dependencies":[{"issue_id":"hcs-1vt","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:42.729783837+01:00","created_by":"gdiazlo","metadata":"{}"}]} 12 + {"id":"hcs-23f","title":"Implement synchronous Stream module (core)","description":"Implement the synchronous Stream module in hcs-core/stream.ml:\n\nProducers:\n- empty, singleton, of_list, of_seq\n- unfold : ('s -\u003e ('a * 's) option) -\u003e 's -\u003e 'a t\n\nTransformers:\n- map, filter, filter_map\n- take, drop, chunks\n\nConsumers:\n- fold, iter, drain\n- to_string (for Cstruct.t streams)\n\nCombinators:\n- concat, zip\n\nThis is the pure, synchronous implementation. Runtime-specific async streams will wrap this.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:28:01.435958367+01:00","updated_at":"2025-12-29T14:51:05.189865738+01:00","closed_at":"2025-12-29T14:51:05.189865738+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-23f","depends_on_id":"hcs-czm","type":"parent-child","created_at":"2025-12-29T14:28:16.036236675+01:00","created_by":"gdiazlo","metadata":"{}"}]} 13 + {"id":"hcs-240","title":"LAS: Main entry point (las.ml)","description":"Endpoint with plug pipeline: Logger, Compress, Session, Csrf, Rate_limit. Start server with WebSocket support.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:42:02.46889176+01:00","updated_at":"2026-01-02T10:28:15.478431398+01:00","closed_at":"2026-01-02T10:28:15.478431398+01:00","dependencies":[{"issue_id":"hcs-240","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:58.522626786+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-240","depends_on_id":"hcs-nwb","type":"blocks","created_at":"2026-01-01T23:43:48.930728118+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-240","depends_on_id":"hcs-q4v","type":"blocks","created_at":"2026-01-01T23:43:53.974339722+01:00","created_by":"gdiazlo","metadata":"{}"}]} 14 + {"id":"hcs-2ca","title":"Implement Eio TLS integration","description":"Implement TLS context creation for Eio runtime in hcs-eio/tls.ml:\n\n- Convert Tls_config.client to Tls.Config.client\n- Convert Tls_config.server to Tls.Config.server \n- Load system certificates using ca-certs\n- Handle ALPN negotiation for HTTP/2\n- Wrap Eio flows with TLS\n\nDepends on tls-eio, ca-certs, x509 packages.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:30:34.350512358+01:00","updated_at":"2025-12-29T15:24:43.224163622+01:00","closed_at":"2025-12-29T15:24:43.224163622+01:00","dependencies":[{"issue_id":"hcs-2ca","depends_on_id":"hcs-y9w","type":"parent-child","created_at":"2025-12-29T14:30:47.016262637+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-2ca","depends_on_id":"hcs-cyb","type":"blocks","created_at":"2025-12-29T14:30:47.870432453+01:00","created_by":"gdiazlo","metadata":"{}"}]} 15 + {"id":"hcs-2emr","title":"docs: Connection Pooling guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:45:02.051465445+01:00","updated_at":"2026-01-03T01:20:01.382508969+01:00","closed_at":"2026-01-03T01:20:01.382508969+01:00"} 16 + {"id":"hcs-2ie","title":"Router Implementation","description":"Implement Path DSL for type-safe extraction and Router module with trie-based route lookup, scoping, and middleware support.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:30.896190732+01:00","updated_at":"2025-12-29T15:41:48.160193387+01:00","closed_at":"2025-12-29T15:41:48.160193387+01:00","dependencies":[{"issue_id":"hcs-2ie","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:15.462426699+01:00","created_by":"gdiazlo","metadata":"{}"}]} 17 + {"id":"hcs-2mr","title":"docs: Server-Sent Events guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:51.121268988+01:00","updated_at":"2026-01-03T01:03:28.19027939+01:00","closed_at":"2026-01-03T01:03:28.19027939+01:00"} 18 + {"id":"hcs-2x6","title":"docs: Request Lifecycle guide","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:44:41.050650054+01:00","updated_at":"2026-01-03T00:53:45.252268207+01:00","closed_at":"2026-01-03T00:53:45.252268207+01:00","dependencies":[{"issue_id":"hcs-2x6","depends_on_id":"hcs-sl6","type":"blocks","created_at":"2026-01-03T00:45:39.414677383+01:00","created_by":"gdiazlo","metadata":"{}"}]} 19 + {"id":"hcs-320","title":"Create benchmark client for load generation","description":"Create a benchmark client (bin/hcs_bench_client.ml) that generates load and measures performance:\n- Configurable concurrency (number of parallel connections)\n- Configurable duration or request count\n- Support for HTTP/1.1 and HTTP/2\n- Measures: requests/second, latency (min/max/avg/p50/p99), errors\n- Reports results in human-readable and JSON formats\n\nShould use Eio fibers for concurrent requests.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T18:03:53.28432088+01:00","updated_at":"2025-12-29T18:15:36.842283087+01:00","closed_at":"2025-12-29T18:15:36.842283087+01:00","dependencies":[{"issue_id":"hcs-320","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:20.175343889+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-320","depends_on_id":"hcs-40d","type":"blocks","created_at":"2025-12-29T18:04:35.617524274+01:00","created_by":"gdiazlo","metadata":"{}"}]} 20 + {"id":"hcs-3dn","title":"Create HCS-based benchmark client for testing all servers","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T22:21:41.677601767+01:00","updated_at":"2025-12-30T22:31:12.664814017+01:00","closed_at":"2025-12-30T22:31:12.664814017+01:00"} 21 + {"id":"hcs-3ww","title":"Middleware System","description":"Implement Middleware module with composition, logging, security (CORS, auth), rate limiting, compression, caching, and static files.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:34.907454455+01:00","updated_at":"2025-12-29T17:40:52.182994384+01:00","closed_at":"2025-12-29T17:40:52.182994384+01:00","dependencies":[{"issue_id":"hcs-3ww","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:19.080036903+01:00","created_by":"gdiazlo","metadata":"{}"}]} 22 + {"id":"hcs-3z0l","title":"Release: Bump version to 0.2.0","description":"Version bump and release:\n- Update dune-project version 0.1.1 → 0.2.0\n- Update hcs.opam if needed\n- Create git tag v0.2.0\n- Ensure CHANGELOG documents breaking changes","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T20:59:50.189811968+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:11:33.400332256+01:00","closed_at":"2026-01-03T21:11:33.400332256+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-3z0l","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:44.80001575+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-3z0l","depends_on_id":"hcs-y4ra","type":"blocks","created_at":"2026-01-03T21:00:48.183373861+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-3z0l","depends_on_id":"hcs-6yzm","type":"blocks","created_at":"2026-01-03T21:00:53.240980402+01:00","created_by":"gdiazlo"}]} 23 + {"id":"hcs-40d","title":"Implement latency histogram and percentile calculations","description":"Create a statistics module (lib/bench_stats.ml or in the benchmark binary) for accurate latency measurements:\n- HDR histogram or simple sorted array for percentiles\n- Calculate min, max, mean, stddev\n- Calculate p50, p90, p95, p99, p99.9 percentiles\n- Track request count, error count, bytes transferred\n- Support for merging stats from multiple workers","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T18:03:57.696657065+01:00","updated_at":"2025-12-29T18:15:29.902324683+01:00","closed_at":"2025-12-29T18:15:29.902324683+01:00","dependencies":[{"issue_id":"hcs-40d","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:22.619809769+01:00","created_by":"gdiazlo","metadata":"{}"}]} 24 + {"id":"hcs-42q","title":"Implement runtime-parameterized async Stream","description":"Design async stream interface that works with both Eio and Lwt:\n\n```ocaml\nmodule type ASYNC_STREAM = sig\n type 'a io\n type 'a t\n \n val from_flow : ... -\u003e Cstruct.t t\n val from_file : ... -\u003e Cstruct.t t\n val to_sink : ... -\u003e Cstruct.t t -\u003e unit io\nend\n\nmodule Make_stream (R : RUNTIME) : ASYNC_STREAM with type 'a io = 'a R.t\n```\n\nThe Eio implementation uses Eio.Flow, the future Lwt version will use Lwt_io.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:28:05.317935403+01:00","updated_at":"2025-12-29T17:08:13.483830721+01:00","closed_at":"2025-12-29T17:08:13.483830721+01:00","labels":["architecture","core"],"dependencies":[{"issue_id":"hcs-42q","depends_on_id":"hcs-czm","type":"parent-child","created_at":"2025-12-29T14:28:16.763534695+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-42q","depends_on_id":"hcs-23f","type":"blocks","created_at":"2025-12-29T14:28:17.658557754+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-42q","depends_on_id":"hcs-6bi","type":"blocks","created_at":"2025-12-29T14:28:18.52508237+01:00","created_by":"gdiazlo","metadata":"{}"}]} 25 + {"id":"hcs-4k8","title":"Fix SSE status OOB swap not working","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-02T19:58:25.962152274+01:00","updated_at":"2026-01-02T21:01:46.748469433+01:00","closed_at":"2026-01-02T21:01:46.748469433+01:00"} 26 + {"id":"hcs-4w8","title":"Create benchmark server with configurable endpoints","description":"Create a dedicated benchmark server (bin/hcs_bench_server.ml) with endpoints optimized for benchmarking:\n- GET /ping - minimal response (measures raw throughput)\n- GET /bytes/:n - returns n bytes (measures payload handling)\n- POST /echo - echoes request body (measures request body parsing)\n- GET /delay/:ms - adds artificial delay (measures concurrency)\n- GET /headers/:n - returns n headers (measures header handling)\n\nServer should support both HTTP/1.1 and HTTP/2, with configurable port and worker count.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T18:03:49.541780606+01:00","updated_at":"2025-12-29T18:15:27.763639409+01:00","closed_at":"2025-12-29T18:15:27.763639409+01:00","dependencies":[{"issue_id":"hcs-4w8","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:17.563056726+01:00","created_by":"gdiazlo","metadata":"{}"}]} 27 + {"id":"hcs-505","title":"Add HTTP/2 benchmark endpoints and comparison scripts","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T00:14:16.705365323+01:00","updated_at":"2025-12-30T00:28:18.304877441+01:00","closed_at":"2025-12-30T00:28:18.304877441+01:00"} 28 + {"id":"hcs-52s","title":"Remove mirage-crypto-rng-eio/unix from tests","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-02T00:23:50.329970611+01:00","updated_at":"2026-01-02T10:16:17.801891715+01:00","closed_at":"2026-01-02T10:16:17.801891715+01:00"} 29 + {"id":"hcs-56z","title":"Implement HTTP/1.1 server parser/serializer","description":"Implement HTTP/1.1 server wire format in hcs-core/h1.ml (extend existing):\n\n```ocaml\n(* Request parsing *)\ntype request_parse_result =\n | Complete of request * int (* request and bytes consumed *)\n | Incomplete of int (* need more bytes *)\n | Error of string\n\nval parse_request_head : Cstruct.t -\u003e request_parse_result\n\n(* Response serialization *)\nval serialize_response : response -\u003e Cstruct.t\nval serialize_response_head : response -\u003e Cstruct.t\n```\n\nPure parsing, zero-copy with Cstruct views.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:19.050407222+01:00","updated_at":"2025-12-29T14:56:39.076056919+01:00","closed_at":"2025-12-29T14:56:39.076056919+01:00","dependencies":[{"issue_id":"hcs-56z","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:41.058840522+01:00","created_by":"gdiazlo","metadata":"{}"}]} 30 + {"id":"hcs-59vc","title":"docs: Responses guide","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:44:56.177760149+01:00","updated_at":"2026-01-03T01:20:01.381157343+01:00","closed_at":"2026-01-03T01:20:01.381157343+01:00"} 31 + {"id":"hcs-5eu","title":"Implement Log module","description":"Implement logging in hcs-core/log.ml:\n\n```ocaml\ntype level = Debug | Info | Warn | Error\n\ntype event =\n | Request_start of { id: string; meth: method_; uri: Uri.t }\n | Request_end of { id: string; status: status; duration_ms: float }\n | Connection_open of { host: string; port: int }\n | Connection_close of { host: string; port: int; reason: string }\n | Connection_reuse of { host: string; port: int }\n | Tls_handshake of { host: string; protocol: string }\n | Retry of { id: string; attempt: int; reason: error }\n | Error of { id: string; error: error }\n\ntype logger = level -\u003e event -\u003e unit\n\n(* Built-in loggers *)\nval null : logger\nval stderr : ?min_level:level -\u003e unit -\u003e logger\nval custom : (level -\u003e string -\u003e unit) -\u003e logger\n\n(* Format event as string *)\nval event_to_string : event -\u003e string\nval level_to_string : level -\u003e string\n```\n\nPure OCaml, no runtime dependency.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:30:26.138649492+01:00","updated_at":"2025-12-29T17:06:37.134220488+01:00","closed_at":"2025-12-29T17:06:37.134220488+01:00","dependencies":[{"issue_id":"hcs-5eu","depends_on_id":"hcs-fgd","type":"parent-child","created_at":"2025-12-29T14:30:45.51204607+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-5eu","depends_on_id":"hcs-gmb","type":"blocks","created_at":"2025-12-29T14:30:48.61530863+01:00","created_by":"gdiazlo","metadata":"{}"}]} 23 32 {"id":"hcs-5wp","title":"Epic: Unified multi-protocol server + comprehensive benchmark suite","description":"Create unified servers (HCS, Hyper, Go) supporting HTTP/1.1, HTTP/2 h2c upgrade, and WebSocket. Build comprehensive benchmark client and automated benchmark runner.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-31T14:13:14.360303024+01:00","updated_at":"2025-12-31T14:47:54.828065477+01:00","closed_at":"2025-12-31T14:47:54.828065477+01:00"} 24 33 {"id":"hcs-62k","title":"LAS: Link Aggregator Service Epic","description":"Tutorial application showcasing HCS features: content negotiation, sessions, CSRF, rate limiting, WebSocket pub/sub, compression. See bin/las/README.md for full tutorial.","status":"closed","priority":1,"issue_type":"epic","created_at":"2026-01-01T23:41:03.971590895+01:00","updated_at":"2026-01-02T00:15:18.204355616+01:00","closed_at":"2026-01-02T00:15:18.204355616+01:00"} 25 - {"id":"hcs-6bi","title":"Design Runtime Abstraction Layer","description":"Design and implement a runtime abstraction layer that allows the library to work with both Eio and Lwt (future). This should include:\n\n1. Define a RUNTIME module signature abstracting:\n - Promise/fiber types ('a t)\n - Concurrency primitives (bind, return, map, both, all)\n - Cancellation tokens\n - Clock/time operations\n - Network operations (connect, listen, read, write)\n - Flow/stream abstractions\n\n2. Structure the library as:\n - `hcs-core`: Pure types, parsers, router trie, codec signatures (no IO)\n - `hcs-eio`: Eio runtime implementation\n - `hcs-lwt`: (future) Lwt runtime implementation\n\n3. Use functors where IO is needed:\n ```ocaml\n module type RUNTIME = sig\n type +'a t\n val return : 'a -\u003e 'a t\n val bind : 'a t -\u003e ('a -\u003e 'b t) -\u003e 'b t\n val both : 'a t -\u003e 'b t -\u003e ('a * 'b) t\n \n module Net : sig ... end\n module Time : sig ... end\n module Cancel : sig ... end\n end\n \n module Make_client (R : RUNTIME) : CLIENT with type 'a io = 'a R.t\n module Make_server (R : RUNTIME) : SERVER with type 'a io = 'a R.t\n ```\n\n4. Keep the core types (request, response, headers, body) runtime-agnostic where possible.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:26:44.115541536+01:00","updated_at":"2025-12-29T15:18:00.901135582+01:00","closed_at":"2025-12-29T15:18:00.901135582+01:00","labels":["architecture","design"],"dependencies":[{"issue_id":"hcs-6bi","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:55.24314139+01:00","created_by":"gdiazlo"}]} 26 - {"id":"hcs-6hx","title":"Create WebSocket benchmark client","description":"Tool to open N concurrent WebSocket connections. Ramp up gradually, keep alive, report success/failure rates. Can target any server.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T10:00:01.720658703+01:00","updated_at":"2025-12-30T10:13:10.676804856+01:00","closed_at":"2025-12-30T10:13:10.676804856+01:00","dependencies":[{"issue_id":"hcs-6hx","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:40.686385073+01:00","created_by":"gdiazlo"}]} 27 - {"id":"hcs-6ki","title":"Create Rust WebSocket benchmark server","description":"Rust server using tokio-tungstenite. Same interface as HCS: accept connections, keep alive, report count.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T09:59:59.970998267+01:00","updated_at":"2025-12-30T10:08:50.863660424+01:00","closed_at":"2025-12-30T10:08:50.863660424+01:00","dependencies":[{"issue_id":"hcs-6ki","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:35.642901603+01:00","created_by":"gdiazlo"}]} 28 - {"id":"hcs-6t7","title":"Create test_plug.ml test file","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:16:46.850226513+01:00","updated_at":"2026-01-01T22:19:33.378942728+01:00","closed_at":"2026-01-01T22:19:33.378942728+01:00"} 29 - {"id":"hcs-6yl","title":"Implement method_ type and helpers","description":"Implement the HTTP method type in types.ml:\n- GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT, TRACE variants\n- to_string/of_string functions\n- Comparison and equality\n\nThis is pure OCaml with no runtime dependency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:08.798345263+01:00","updated_at":"2025-12-29T14:50:42.057204391+01:00","closed_at":"2025-12-29T14:50:42.057204391+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-6yl","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:38.28650235+01:00","created_by":"gdiazlo"}]} 30 - {"id":"hcs-763","title":"Create HTTP/1.1 server compliance tests","description":"Create comprehensive HTTP/1.1 server tests using curl and custom test client:\n\nTest categories (based on RFC 7230-7235):\n\n1. **Request parsing:**\n - Valid/invalid request lines\n - Header field parsing (folding, whitespace)\n - Host header requirement\n - Content-Length handling\n - Transfer-Encoding: chunked\n\n2. **Response generation:**\n - Status line format\n - Required headers (Date, Content-Length/Transfer-Encoding)\n - Connection: close/keep-alive\n\n3. **Methods:**\n - HEAD returns no body\n - OPTIONS with Allow header\n - TRACE (if supported)\n - Unknown methods\n\n4. **Connection management:**\n - Keep-alive (HTTP/1.1 default)\n - Pipelining support\n - Connection: close handling\n - Timeout behavior\n\n5. **Error handling:**\n - 400 Bad Request (malformed)\n - 405 Method Not Allowed\n - 411 Length Required\n - 413 Payload Too Large\n - 414 URI Too Long\n - 431 Request Header Fields Too Large\n - 501 Not Implemented\n\n6. **Edge cases:**\n - Empty body vs no body\n - Zero Content-Length\n - Multiple Content-Length headers (reject)\n - LF vs CRLF tolerance","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:24.121658164+01:00","updated_at":"2025-12-29T17:52:19.19217344+01:00","closed_at":"2025-12-29T17:52:19.19217344+01:00","dependencies":[{"issue_id":"hcs-763","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:50.138423904+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-763","depends_on_id":"hcs-cyk","type":"blocks","created_at":"2025-12-29T14:36:59.919859607+01:00","created_by":"gdiazlo"}]} 31 - {"id":"hcs-7c6","title":"Add compression middleware tests","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:21.503420164+01:00","updated_at":"2026-01-01T20:27:15.06105377+01:00","closed_at":"2026-01-01T20:27:15.06105377+01:00","dependencies":[{"issue_id":"hcs-7c6","depends_on_id":"hcs-rvk","type":"blocks","created_at":"2026-01-01T18:44:51.69538876+01:00","created_by":"gdiazlo"}]} 32 - {"id":"hcs-7dw","title":"Run benchmarks after optimizations","description":"Re-run single-CPU benchmarks with run_h2_comparison.sh --single-cpu to measure improvement.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:57:27.925408893+01:00","updated_at":"2025-12-30T09:01:48.794721842+01:00","closed_at":"2025-12-30T09:01:48.794721842+01:00","dependencies":[{"issue_id":"hcs-7dw","depends_on_id":"hcs-cq4","type":"parent-child","created_at":"2025-12-30T08:57:54.882328415+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-7dw","depends_on_id":"hcs-f2r","type":"blocks","created_at":"2025-12-30T08:57:59.924301728+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-7dw","depends_on_id":"hcs-jqx","type":"blocks","created_at":"2025-12-30T08:58:04.960054323+01:00","created_by":"gdiazlo"}]} 33 - {"id":"hcs-7my","title":"Implement zero-copy optimizations in H2_server (Body_bigstring, Body_prebuilt)","description":"","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-12-30T00:14:14.612100017+01:00","updated_at":"2025-12-30T00:19:21.483563727+01:00","closed_at":"2025-12-30T00:19:21.483563727+01:00"} 34 - {"id":"hcs-7n9","title":"Implement HTTP/1.1 client (Eio)","description":"Implement HTTP/1.1 client for Eio in hcs-eio/h1_client.ml:\n\n```ocaml\nval request :\n flow:Eio.Flow.two_way -\u003e\n clock:Eio.Time.clock -\u003e\n config:Client.config -\u003e\n ?cancel:Cancel.t -\u003e\n request -\u003e\n (response, error) result\n```\n\nFeatures:\n- Send request, read response using h1 parser\n- Handle Content-Length and chunked bodies\n- Support streaming response body\n- Respect timeouts from config\n- Handle keep-alive\n- Integrate with logging","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:20.182355085+01:00","updated_at":"2025-12-29T15:03:26.826860172+01:00","closed_at":"2025-12-29T15:03:26.826860172+01:00","dependencies":[{"issue_id":"hcs-7n9","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:48.505518121+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-7n9","depends_on_id":"hcs-8zr","type":"blocks","created_at":"2025-12-29T14:31:52.981022505+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-7n9","depends_on_id":"hcs-kg1","type":"blocks","created_at":"2025-12-29T14:31:53.49623941+01:00","created_by":"gdiazlo"}]} 34 + {"id":"hcs-6bi","title":"Design Runtime Abstraction Layer","description":"Design and implement a runtime abstraction layer that allows the library to work with both Eio and Lwt (future). This should include:\n\n1. Define a RUNTIME module signature abstracting:\n - Promise/fiber types ('a t)\n - Concurrency primitives (bind, return, map, both, all)\n - Cancellation tokens\n - Clock/time operations\n - Network operations (connect, listen, read, write)\n - Flow/stream abstractions\n\n2. Structure the library as:\n - `hcs-core`: Pure types, parsers, router trie, codec signatures (no IO)\n - `hcs-eio`: Eio runtime implementation\n - `hcs-lwt`: (future) Lwt runtime implementation\n\n3. Use functors where IO is needed:\n ```ocaml\n module type RUNTIME = sig\n type +'a t\n val return : 'a -\u003e 'a t\n val bind : 'a t -\u003e ('a -\u003e 'b t) -\u003e 'b t\n val both : 'a t -\u003e 'b t -\u003e ('a * 'b) t\n \n module Net : sig ... end\n module Time : sig ... end\n module Cancel : sig ... end\n end\n \n module Make_client (R : RUNTIME) : CLIENT with type 'a io = 'a R.t\n module Make_server (R : RUNTIME) : SERVER with type 'a io = 'a R.t\n ```\n\n4. Keep the core types (request, response, headers, body) runtime-agnostic where possible.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:26:44.115541536+01:00","updated_at":"2025-12-29T15:18:00.901135582+01:00","closed_at":"2025-12-29T15:18:00.901135582+01:00","labels":["architecture","design"],"dependencies":[{"issue_id":"hcs-6bi","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:55.24314139+01:00","created_by":"gdiazlo","metadata":"{}"}]} 35 + {"id":"hcs-6dx","title":"docs: Plug System guide","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:44:51.137604372+01:00","updated_at":"2026-01-03T00:56:49.636574616+01:00","closed_at":"2026-01-03T00:56:49.636574616+01:00","dependencies":[{"issue_id":"hcs-6dx","depends_on_id":"hcs-sl6","type":"blocks","created_at":"2026-01-03T00:45:49.4963709+01:00","created_by":"gdiazlo","metadata":"{}"}]} 36 + {"id":"hcs-6hx","title":"Create WebSocket benchmark client","description":"Tool to open N concurrent WebSocket connections. Ramp up gradually, keep alive, report success/failure rates. Can target any server.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T10:00:01.720658703+01:00","updated_at":"2025-12-30T10:13:10.676804856+01:00","closed_at":"2025-12-30T10:13:10.676804856+01:00","dependencies":[{"issue_id":"hcs-6hx","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:40.686385073+01:00","created_by":"gdiazlo","metadata":"{}"}]} 37 + {"id":"hcs-6ki","title":"Create Rust WebSocket benchmark server","description":"Rust server using tokio-tungstenite. Same interface as HCS: accept connections, keep alive, report count.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T09:59:59.970998267+01:00","updated_at":"2025-12-30T10:08:50.863660424+01:00","closed_at":"2025-12-30T10:08:50.863660424+01:00","dependencies":[{"issue_id":"hcs-6ki","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:35.642901603+01:00","created_by":"gdiazlo","metadata":"{}"}]} 38 + {"id":"hcs-6t7","title":"Create test_plug.ml test file","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:16:46.850226513+01:00","updated_at":"2026-01-01T22:19:33.378942728+01:00","closed_at":"2026-01-01T22:19:33.378942728+01:00"} 39 + {"id":"hcs-6yl","title":"Implement method_ type and helpers","description":"Implement the HTTP method type in types.ml:\n- GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT, TRACE variants\n- to_string/of_string functions\n- Comparison and equality\n\nThis is pure OCaml with no runtime dependency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:08.798345263+01:00","updated_at":"2025-12-29T14:50:42.057204391+01:00","closed_at":"2025-12-29T14:50:42.057204391+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-6yl","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:38.28650235+01:00","created_by":"gdiazlo","metadata":"{}"}]} 40 + {"id":"hcs-6yzm","title":"Update: Documentation for v0.2.0","description":"Update documentation:\n- README.md: Update module table, update Endpoint→App\n- bin/las/README.md: Update tutorial code examples\n- lib/app.ml: Add comprehensive module documentation\n- Add CHANGELOG.md entry for breaking change\n- Add migration guide section","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T20:59:46.293078367+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:11:23.303045148+01:00","closed_at":"2026-01-03T21:11:23.303045148+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-6yzm","depends_on_id":"hcs-j7fj","type":"blocks","created_at":"2026-01-03T21:00:27.960329201+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-6yzm","depends_on_id":"hcs-lskj","type":"blocks","created_at":"2026-01-03T21:00:33.015016797+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-6yzm","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:34.690634709+01:00","created_by":"gdiazlo"}]} 41 + {"id":"hcs-763","title":"Create HTTP/1.1 server compliance tests","description":"Create comprehensive HTTP/1.1 server tests using curl and custom test client:\n\nTest categories (based on RFC 7230-7235):\n\n1. **Request parsing:**\n - Valid/invalid request lines\n - Header field parsing (folding, whitespace)\n - Host header requirement\n - Content-Length handling\n - Transfer-Encoding: chunked\n\n2. **Response generation:**\n - Status line format\n - Required headers (Date, Content-Length/Transfer-Encoding)\n - Connection: close/keep-alive\n\n3. **Methods:**\n - HEAD returns no body\n - OPTIONS with Allow header\n - TRACE (if supported)\n - Unknown methods\n\n4. **Connection management:**\n - Keep-alive (HTTP/1.1 default)\n - Pipelining support\n - Connection: close handling\n - Timeout behavior\n\n5. **Error handling:**\n - 400 Bad Request (malformed)\n - 405 Method Not Allowed\n - 411 Length Required\n - 413 Payload Too Large\n - 414 URI Too Long\n - 431 Request Header Fields Too Large\n - 501 Not Implemented\n\n6. **Edge cases:**\n - Empty body vs no body\n - Zero Content-Length\n - Multiple Content-Length headers (reject)\n - LF vs CRLF tolerance","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:24.121658164+01:00","updated_at":"2025-12-29T17:52:19.19217344+01:00","closed_at":"2025-12-29T17:52:19.19217344+01:00","dependencies":[{"issue_id":"hcs-763","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:50.138423904+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-763","depends_on_id":"hcs-cyk","type":"blocks","created_at":"2025-12-29T14:36:59.919859607+01:00","created_by":"gdiazlo","metadata":"{}"}]} 42 + {"id":"hcs-7c6","title":"Add compression middleware tests","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:21.503420164+01:00","updated_at":"2026-01-01T20:27:15.06105377+01:00","closed_at":"2026-01-01T20:27:15.06105377+01:00","dependencies":[{"issue_id":"hcs-7c6","depends_on_id":"hcs-rvk","type":"blocks","created_at":"2026-01-01T18:44:51.69538876+01:00","created_by":"gdiazlo","metadata":"{}"}]} 43 + {"id":"hcs-7dw","title":"Run benchmarks after optimizations","description":"Re-run single-CPU benchmarks with run_h2_comparison.sh --single-cpu to measure improvement.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:57:27.925408893+01:00","updated_at":"2025-12-30T09:01:48.794721842+01:00","closed_at":"2025-12-30T09:01:48.794721842+01:00","dependencies":[{"issue_id":"hcs-7dw","depends_on_id":"hcs-cq4","type":"parent-child","created_at":"2025-12-30T08:57:54.882328415+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-7dw","depends_on_id":"hcs-f2r","type":"blocks","created_at":"2025-12-30T08:57:59.924301728+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-7dw","depends_on_id":"hcs-jqx","type":"blocks","created_at":"2025-12-30T08:58:04.960054323+01:00","created_by":"gdiazlo","metadata":"{}"}]} 44 + {"id":"hcs-7my","title":"Implement zero-copy optimizations in H2_server (Body_bigstring, Body_prebuilt)","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-12-30T00:14:14.612100017+01:00","updated_at":"2025-12-30T00:19:21.483563727+01:00","closed_at":"2025-12-30T00:19:21.483563727+01:00"} 45 + {"id":"hcs-7n9","title":"Implement HTTP/1.1 client (Eio)","description":"Implement HTTP/1.1 client for Eio in hcs-eio/h1_client.ml:\n\n```ocaml\nval request :\n flow:Eio.Flow.two_way -\u003e\n clock:Eio.Time.clock -\u003e\n config:Client.config -\u003e\n ?cancel:Cancel.t -\u003e\n request -\u003e\n (response, error) result\n```\n\nFeatures:\n- Send request, read response using h1 parser\n- Handle Content-Length and chunked bodies\n- Support streaming response body\n- Respect timeouts from config\n- Handle keep-alive\n- Integrate with logging","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:20.182355085+01:00","updated_at":"2025-12-29T15:03:26.826860172+01:00","closed_at":"2025-12-29T15:03:26.826860172+01:00","dependencies":[{"issue_id":"hcs-7n9","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:48.505518121+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-7n9","depends_on_id":"hcs-8zr","type":"blocks","created_at":"2025-12-29T14:31:52.981022505+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-7n9","depends_on_id":"hcs-kg1","type":"blocks","created_at":"2025-12-29T14:31:53.49623941+01:00","created_by":"gdiazlo","metadata":"{}"}]} 46 + {"id":"hcs-7neb","title":"Test: Full test suite + manual verification","description":"Verify everything works:\n\n1. dune build - no errors\n2. dune test - all tests pass\n3. Run las application manually\n4. Test different pipelines work (browser vs api)\n5. Test per-route plugs work\n6. Test endpoint global plugs work","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:12:13.565207511+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:31:21.011769207+01:00","closed_at":"2026-01-03T21:31:21.011769207+01:00","close_reason":"All tests pass","dependencies":[{"issue_id":"hcs-7neb","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:13:14.777792609+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-7neb","depends_on_id":"hcs-9076","type":"blocks","created_at":"2026-01-03T21:14:20.50091636+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-7neb","depends_on_id":"hcs-qio9","type":"blocks","created_at":"2026-01-03T21:14:25.558307736+01:00","created_by":"gdiazlo"}]} 47 + {"id":"hcs-7su","title":"docs: First Client guide","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T00:44:28.442572789+01:00","updated_at":"2026-01-03T00:51:36.947713258+01:00","closed_at":"2026-01-03T00:51:36.947713258+01:00","dependencies":[{"issue_id":"hcs-7su","depends_on_id":"hcs-vjo","type":"blocks","created_at":"2026-01-03T00:45:34.377118144+01:00","created_by":"gdiazlo","metadata":"{}"}]} 48 + {"id":"hcs-7zig","title":"Add Response.Cstruct body variant to avoid string conversions","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T11:32:29.204582381+01:00","updated_at":"2026-01-03T11:35:34.369060418+01:00","closed_at":"2026-01-03T11:35:34.369060418+01:00"} 35 49 {"id":"hcs-82y","title":"HTTP/2 Performance Comparison: HCS vs Rust vs Go","description":"Compare HTTP/2 server performance across HCS (OCaml), Rust (hyper/axum), and Go (net/http). Focus on throughput, latency, and resource usage under various workloads.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-30T08:21:37.583365059+01:00","updated_at":"2025-12-30T08:49:54.887556286+01:00","closed_at":"2025-12-30T08:49:54.887556286+01:00"} 36 - {"id":"hcs-883","title":"Add tests for remaining plugs: Compress, Cors, Csrf, Basic_auth, Retry, Static","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:24:54.008491291+01:00","updated_at":"2026-01-01T22:35:25.772956789+01:00","closed_at":"2026-01-01T22:35:25.772956789+01:00"} 37 - {"id":"hcs-8br","title":"Implement Cancel module","description":"Implement cooperative cancellation in hcs-core/cancel.ml:\n\n```ocaml\nmodule Cancel : sig\n type t\n \n val create : unit -\u003e t\n val cancel : t -\u003e unit\n val is_cancelled : t -\u003e bool\n val check : t -\u003e (unit, error) result (* Returns Error Cancelled if cancelled *)\n \n (* Combine multiple tokens - cancelled if any is cancelled *)\n val any : t list -\u003e t\nend\n```\n\nImplementation: Use an Atomic.t bool internally for thread-safety. The `any` combinator creates a new token that polls children.\n\nThis is the core, runtime-agnostic cancellation. Runtime-specific implementations (Eio.Cancel, Lwt.cancel) will wrap this or provide their own.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:29:20.005246967+01:00","updated_at":"2025-12-29T14:56:31.063102088+01:00","closed_at":"2025-12-29T14:56:31.063102088+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-8br","depends_on_id":"hcs-pnc","type":"parent-child","created_at":"2025-12-29T14:30:09.074639524+01:00","created_by":"gdiazlo"}]} 38 - {"id":"hcs-8zr","title":"Implement HTTP/1.1 client parser/serializer","description":"Implement HTTP/1.1 wire format in hcs-core/h1.ml:\n\n```ocaml\n(* Request serialization *)\nval serialize_request : request -\u003e Cstruct.t\nval serialize_request_head : request -\u003e Cstruct.t (* without body *)\n\n(* Response parsing *)\ntype parse_result = \n | Complete of response * int (* response and bytes consumed *)\n | Incomplete of int (* need more bytes, minimum *)\n | Error of string\n\nval parse_response_head : Cstruct.t -\u003e parse_result\n\n(* Chunked transfer encoding *)\nval parse_chunk_header : Cstruct.t -\u003e (int * int, string) result (* size, header_len *)\nval serialize_chunk : Cstruct.t -\u003e Cstruct.t\nval serialize_last_chunk : Cstruct.t\n```\n\nPure parsing/serialization, no IO. Use zero-copy where possible with Cstruct views.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:17.431899471+01:00","updated_at":"2025-12-29T14:56:37.246977449+01:00","closed_at":"2025-12-29T14:56:37.246977449+01:00","dependencies":[{"issue_id":"hcs-8zr","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:46.61571522+01:00","created_by":"gdiazlo"}]} 39 - {"id":"hcs-9dz","title":"Clean up duplicate implementations: remove non-optimized functions and rename optimized ones","description":"","status":"closed","priority":1,"issue_type":"chore","created_at":"2025-12-30T21:00:09.361966265+01:00","updated_at":"2025-12-30T21:08:48.343581414+01:00","closed_at":"2025-12-30T21:08:48.343581414+01:00"} 40 - {"id":"hcs-9mk","title":"Replace Printf.sprintf usage in lib/*.ml","description":"","notes":"Rescanned lib for Printf.(k)sprintf: only remaining uses are in lib/buf.ml float helpers (kept) and lib/websocket.ml. Replaced websocket opcode Ctrl/Nonctrl Printf.sprintf with manual decimal int conversion + concatenation. dune build and dune test pass.","status":"in_progress","priority":2,"issue_type":"task","created_at":"2026-01-02T12:31:16.255651395+01:00","updated_at":"2026-01-02T12:37:29.215378699+01:00"} 41 - {"id":"hcs-9y1","title":"Implement Client.config type","description":"Implement client configuration in hcs-core/client_config.ml:\n\n```ocaml\ntype config = {\n (* Connection pooling *)\n max_connections_per_host : int; (* default: 100 *)\n max_total_connections : int; (* default: 1000 *)\n idle_timeout : float; (* seconds, default: 60.0 *)\n\n (* Timeouts *)\n connect_timeout : float; (* default: 30.0 *)\n read_timeout : float; (* default: 30.0 *)\n write_timeout : float; (* default: 30.0 *)\n\n (* Behavior *)\n follow_redirects : int option; (* None = don't follow, default: Some 10 *)\n http2_prior_knowledge : bool; (* default: false *)\n\n (* Buffers *)\n buffer_size : int; (* default: 16384 *)\n max_response_body : int64 option; (* None = unlimited *)\n\n (* TLS *)\n tls : Tls_config.client option;\n\n (* Compression *)\n accept_compression : bool; (* default: true *)\n decompress_response : bool; (* default: true *)\n\n (* Logging *)\n logger : Log.logger; (* default: Log.null *)\n}\n\nval default : config\nval with_timeout : float -\u003e config -\u003e config\nval with_max_connections : int -\u003e config -\u003e config\n(* ... other builders ... *)\n```\n\nPure configuration, no IO.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:05.431230385+01:00","updated_at":"2025-12-29T15:40:22.434194947+01:00","closed_at":"2025-12-29T15:40:22.434194947+01:00","dependencies":[{"issue_id":"hcs-9y1","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:42.307867928+01:00","created_by":"gdiazlo"}]} 42 - {"id":"hcs-9yc","title":"Go: Unified server with HTTP/1.1 + h2c + WebSocket","description":"Update Go net/http server to handle HTTP/1.1, h2c, and WebSocket on single port.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:36.193925748+01:00","updated_at":"2025-12-31T14:26:13.33110701+01:00","closed_at":"2025-12-31T14:26:13.33110701+01:00","dependencies":[{"issue_id":"hcs-9yc","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:30.935375958+01:00","created_by":"gdiazlo"}]} 43 - {"id":"hcs-ag6","title":"Implement H2 module (HTTP/2 specific features)","description":"Implement HTTP/2 specific features in hcs-eio/h2.ml:\n\n```ocaml\n(* Server push *)\nval push : request -\u003e Uri.t -\u003e (unit, error) result\n\n(* Stream priority *)\ntype priority = {\n dependency : int32;\n weight : int; (* 1-256 *)\n exclusive : bool;\n}\n\nval set_priority : priority -\u003e (unit, error) result\n\n(* Check protocol *)\nval is_h2 : request -\u003e bool\n```\n\nLower priority - can be added after basic HTTP/2 works.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-29T14:34:36.59579057+01:00","updated_at":"2025-12-29T17:39:24.986755909+01:00","closed_at":"2025-12-29T17:39:24.986755909+01:00","dependencies":[{"issue_id":"hcs-ag6","depends_on_id":"hcs-1uy","type":"parent-child","created_at":"2025-12-29T14:34:53.890566238+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-ag6","depends_on_id":"hcs-d5s","type":"blocks","created_at":"2025-12-29T14:34:58.997623679+01:00","created_by":"gdiazlo"}]} 44 - {"id":"hcs-ajr","title":"Compare HCS performance against external tools (wrk, hey)","description":"Validate HCS benchmark results by comparing against established tools:\n- Use wrk or hey to benchmark HCS server\n- Compare results with HCS benchmark client\n- Document any discrepancies\n- This validates both our server performance and benchmark accuracy\n\nOptional: Add script to run comparison benchmarks.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-29T18:04:05.806924896+01:00","updated_at":"2025-12-29T18:18:13.778810608+01:00","closed_at":"2025-12-29T18:18:13.778810608+01:00","dependencies":[{"issue_id":"hcs-ajr","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:25.893845517+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-ajr","depends_on_id":"hcs-4w8","type":"blocks","created_at":"2025-12-29T18:04:39.385790421+01:00","created_by":"gdiazlo"}]} 45 - {"id":"hcs-ax6","title":"Implement With_codec functor","description":"Implement the With_codec functor in hcs-core/codec.ml:\n\n```ocaml\nmodule With_codec (C : CODEC) : sig\n val encode_body : 'a C.encoder -\u003e 'a -\u003e (body, error) result\n val decode_body : 'a C.decoder -\u003e body -\u003e ('a, error) result\n\n (* Request helpers *)\n val set_body : 'a C.encoder -\u003e 'a -\u003e request -\u003e (request, error) result\n\n (* Response helpers *) \n val read_body : 'a C.decoder -\u003e response -\u003e ('a, error) result\n val make_response : ?status:status -\u003e 'a C.encoder -\u003e 'a -\u003e (response, error) result\nend\n```\n\nThe functor should:\n- Handle body type variants (Empty, Fixed, Stream, File)\n- Set appropriate Content-Type header from C.content_type\n- Convert between Cstruct.t and body types\n- Propagate codec errors as Codec_error\n\nPure OCaml, depends on types.ml and error.ml.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:28:47.94509919+01:00","updated_at":"2025-12-29T17:04:35.621002337+01:00","closed_at":"2025-12-29T17:04:35.621002337+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-ax6","depends_on_id":"hcs-m4r","type":"parent-child","created_at":"2025-12-29T14:29:00.595372107+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-ax6","depends_on_id":"hcs-pwc","type":"blocks","created_at":"2025-12-29T14:29:02.656963585+01:00","created_by":"gdiazlo"}]} 46 - {"id":"hcs-b83","title":"Implement Endpoint module","description":"Clean application bootstrap tying router, plugs, and server together.\n\n## Design\n\n### Core API\n```ocaml\nmodule Endpoint : sig\n type t\n type config = {\n port: int;\n bind: string;\n domains: int;\n secret_key_base: string;\n (* TLS, HTTP version, etc. *)\n }\n \n val create : config -\u003e t\n val plug : t -\u003e Plug.t -\u003e t\n val router : t -\u003e Router.t -\u003e t\n val start : t -\u003e env:Eio.Stdenv.t -\u003e unit\nend\n```\n\n### Usage\n```ocaml\nlet () =\n Endpoint.create config\n |\u003e Endpoint.plug (Plug.Logger.create ())\n |\u003e Endpoint.plug (Plug.Session.create ~store ())\n |\u003e Endpoint.plug (Plug.Csrf.create ())\n |\u003e Endpoint.router my_router\n |\u003e Endpoint.start ~env\n```\n\n### Features\n1. **Plug pipeline** - Ordered list of plugs applied to all requests\n2. **Router integration** - Final handler from router\n3. **Error handling** - Catch-all error responses\n4. **Graceful shutdown** - Handle SIGTERM/SIGINT\n5. **Health check** - Built-in /_health endpoint (optional)\n\n### Implementation\n- Composes plugs at startup (no runtime list traversal)\n- Passes config to plugs that need it (session secret, etc.)\n- Single Server.start call with composed handler\n\n### Performance\n- All composition happens at startup\n- Handler is a single function, no dynamic dispatch\n- Zero per-request allocation for endpoint logic","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:23.386314333+01:00","updated_at":"2026-01-01T21:30:28.400524063+01:00","closed_at":"2026-01-01T21:30:28.400524063+01:00","dependencies":[{"issue_id":"hcs-b83","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:48:06.720271707+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-b83","depends_on_id":"hcs-d0n","type":"blocks","created_at":"2026-01-01T20:48:16.796430672+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-b83","depends_on_id":"hcs-oqc","type":"blocks","created_at":"2026-01-01T20:48:21.832567305+01:00","created_by":"gdiazlo"}]} 47 - {"id":"hcs-bea","title":"Implement core middleware combinators","description":"Implement middleware composition in hcs-core/middleware.ml:\n\n```ocaml\ntype middleware = (request -\u003e (response, error) result) -\u003e request -\u003e (response, error) result\n\n(* Composition *)\nval ( @\u003e ) : middleware -\u003e middleware -\u003e middleware\nval compose : middleware list -\u003e middleware\nval identity : middleware\n\n(* Pure middleware (no IO needed) *)\nval default_headers : (string * string) list -\u003e middleware\nval catch_errors : (error -\u003e response) -\u003e middleware\nval body_limit : int64 -\u003e middleware\nval request_id : ?header:string -\u003e ?generator:(unit -\u003e string) -\u003e unit -\u003e middleware\n\n(* Security headers *)\nval security_headers : middleware\nval cors :\n ?origins:[ `All | `List of string list ] -\u003e\n ?methods:method_ list -\u003e\n ?headers:string list -\u003e\n ?max_age:int -\u003e\n ?credentials:bool -\u003e\n unit -\u003e\n middleware\n\n(* Auth - validation functions are pure *)\nval basic_auth : realm:string -\u003e validate:(user:string -\u003e pass:string -\u003e bool) -\u003e middleware\nval bearer_auth : validate:(token:string -\u003e bool) -\u003e middleware\n```\n\nPure OCaml.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:27.663177003+01:00","updated_at":"2025-12-29T15:18:06.262737908+01:00","closed_at":"2025-12-29T15:18:06.262737908+01:00","dependencies":[{"issue_id":"hcs-bea","depends_on_id":"hcs-3ww","type":"parent-child","created_at":"2025-12-29T14:34:50.365242865+01:00","created_by":"gdiazlo"}]} 48 - {"id":"hcs-chm","title":"Implement body type","description":"Implement the body type in types.ml:\n- Empty variant\n- Fixed of string variant\n- Stream of (unit -\u003e Cstruct.t option) - pull-based streaming\n- File of string * int64 * int64 (path, offset, length)\n\nNote: The Stream variant uses a function type that is runtime-agnostic. For async streaming, we'll need a runtime-parameterized body type in the IO layer.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:16.560667848+01:00","updated_at":"2025-12-29T14:50:45.579783806+01:00","closed_at":"2025-12-29T14:50:45.579783806+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-chm","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:40.664331169+01:00","created_by":"gdiazlo"}]} 49 - {"id":"hcs-cks","title":"Implement Headers module","description":"Implement case-insensitive header map in headers.ml:\n- type t (backed by Map with lowercase keys)\n- empty, singleton, add, add_list\n- find, find_all, remove, mem\n- fold, to_list, of_list\n- Consider using a more efficient representation (e.g., sorted list for small headers)\n\nPure OCaml, no runtime dependency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:12.768404369+01:00","updated_at":"2025-12-29T14:50:44.414829218+01:00","closed_at":"2025-12-29T14:50:44.414829218+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-cks","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:39.839372964+01:00","created_by":"gdiazlo"}]} 50 - {"id":"hcs-cmg","title":"Implement version type","description":"Implement the HTTP version type:\n- HTTP_1_1, HTTP_2 variants\n- to_string/of_string functions\n\nPure OCaml, no runtime dependency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:10.081239709+01:00","updated_at":"2025-12-29T14:50:42.943845373+01:00","closed_at":"2025-12-29T14:50:42.943845373+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-cmg","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:39.140549859+01:00","created_by":"gdiazlo"}]} 50 + {"id":"hcs-883","title":"Add tests for remaining plugs: Compress, Cors, Csrf, Basic_auth, Retry, Static","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:24:54.008491291+01:00","updated_at":"2026-01-01T22:35:25.772956789+01:00","closed_at":"2026-01-01T22:35:25.772956789+01:00"} 51 + {"id":"hcs-8br","title":"Implement Cancel module","description":"Implement cooperative cancellation in hcs-core/cancel.ml:\n\n```ocaml\nmodule Cancel : sig\n type t\n \n val create : unit -\u003e t\n val cancel : t -\u003e unit\n val is_cancelled : t -\u003e bool\n val check : t -\u003e (unit, error) result (* Returns Error Cancelled if cancelled *)\n \n (* Combine multiple tokens - cancelled if any is cancelled *)\n val any : t list -\u003e t\nend\n```\n\nImplementation: Use an Atomic.t bool internally for thread-safety. The `any` combinator creates a new token that polls children.\n\nThis is the core, runtime-agnostic cancellation. Runtime-specific implementations (Eio.Cancel, Lwt.cancel) will wrap this or provide their own.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:29:20.005246967+01:00","updated_at":"2025-12-29T14:56:31.063102088+01:00","closed_at":"2025-12-29T14:56:31.063102088+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-8br","depends_on_id":"hcs-pnc","type":"parent-child","created_at":"2025-12-29T14:30:09.074639524+01:00","created_by":"gdiazlo","metadata":"{}"}]} 52 + {"id":"hcs-8zr","title":"Implement HTTP/1.1 client parser/serializer","description":"Implement HTTP/1.1 wire format in hcs-core/h1.ml:\n\n```ocaml\n(* Request serialization *)\nval serialize_request : request -\u003e Cstruct.t\nval serialize_request_head : request -\u003e Cstruct.t (* without body *)\n\n(* Response parsing *)\ntype parse_result = \n | Complete of response * int (* response and bytes consumed *)\n | Incomplete of int (* need more bytes, minimum *)\n | Error of string\n\nval parse_response_head : Cstruct.t -\u003e parse_result\n\n(* Chunked transfer encoding *)\nval parse_chunk_header : Cstruct.t -\u003e (int * int, string) result (* size, header_len *)\nval serialize_chunk : Cstruct.t -\u003e Cstruct.t\nval serialize_last_chunk : Cstruct.t\n```\n\nPure parsing/serialization, no IO. Use zero-copy where possible with Cstruct views.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:17.431899471+01:00","updated_at":"2025-12-29T14:56:37.246977449+01:00","closed_at":"2025-12-29T14:56:37.246977449+01:00","dependencies":[{"issue_id":"hcs-8zr","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:46.61571522+01:00","created_by":"gdiazlo","metadata":"{}"}]} 53 + {"id":"hcs-9076","title":"Update: Migrate las.ml to new architecture","description":"Rewrite bin/las/las.ml using new three-layer architecture:\n\n1. Endpoint with global plugs (logger, session, static)\n2. Router with pipelines (browser pipeline for web, api pipeline for JSON)\n3. Per-route plugs where needed (auth on protected routes)\n\nThis validates the new API design works in practice.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:12:08.460666471+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:31:10.900440039+01:00","closed_at":"2026-01-03T21:31:10.900440039+01:00","close_reason":"Migrated las.ml","dependencies":[{"issue_id":"hcs-9076","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:13:04.669576954+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-9076","depends_on_id":"hcs-cf24","type":"blocks","created_at":"2026-01-03T21:14:00.272954069+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-9076","depends_on_id":"hcs-z64a","type":"blocks","created_at":"2026-01-03T21:14:05.330540394+01:00","created_by":"gdiazlo"}]} 54 + {"id":"hcs-9dz","title":"Clean up duplicate implementations: remove non-optimized functions and rename optimized ones","status":"closed","priority":1,"issue_type":"chore","created_at":"2025-12-30T21:00:09.361966265+01:00","updated_at":"2025-12-30T21:08:48.343581414+01:00","closed_at":"2025-12-30T21:08:48.343581414+01:00"} 55 + {"id":"hcs-9gav","title":"docs: Plugs Reference (all built-in plugs)","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:44:53.585873271+01:00","updated_at":"2026-01-03T01:03:38.273529229+01:00","closed_at":"2026-01-03T01:03:38.273529229+01:00"} 56 + {"id":"hcs-9l7","title":"docs: Writing Custom Plugs guide","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:44:48.545112929+01:00","updated_at":"2026-01-03T01:20:01.380747222+01:00","closed_at":"2026-01-03T01:20:01.380747222+01:00"} 57 + {"id":"hcs-9mk","title":"Replace Printf.sprintf usage in lib/*.ml","notes":"Rescanned lib for Printf.(k)sprintf: only remaining uses are in lib/buf.ml float helpers (kept) and lib/websocket.ml. Replaced websocket opcode Ctrl/Nonctrl Printf.sprintf with manual decimal int conversion + concatenation. dune build and dune test pass.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T12:31:16.255651395+01:00","updated_at":"2026-01-02T12:40:31.100451175+01:00","closed_at":"2026-01-02T12:40:31.100451175+01:00"} 58 + {"id":"hcs-9xm","title":"docs: Routing guide","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:44:46.093510133+01:00","updated_at":"2026-01-03T00:55:12.750145669+01:00","closed_at":"2026-01-03T00:55:12.750145669+01:00","dependencies":[{"issue_id":"hcs-9xm","depends_on_id":"hcs-sl6","type":"blocks","created_at":"2026-01-03T00:45:44.45274747+01:00","created_by":"gdiazlo","metadata":"{}"}]} 59 + {"id":"hcs-9y1","title":"Implement Client.config type","description":"Implement client configuration in hcs-core/client_config.ml:\n\n```ocaml\ntype config = {\n (* Connection pooling *)\n max_connections_per_host : int; (* default: 100 *)\n max_total_connections : int; (* default: 1000 *)\n idle_timeout : float; (* seconds, default: 60.0 *)\n\n (* Timeouts *)\n connect_timeout : float; (* default: 30.0 *)\n read_timeout : float; (* default: 30.0 *)\n write_timeout : float; (* default: 30.0 *)\n\n (* Behavior *)\n follow_redirects : int option; (* None = don't follow, default: Some 10 *)\n http2_prior_knowledge : bool; (* default: false *)\n\n (* Buffers *)\n buffer_size : int; (* default: 16384 *)\n max_response_body : int64 option; (* None = unlimited *)\n\n (* TLS *)\n tls : Tls_config.client option;\n\n (* Compression *)\n accept_compression : bool; (* default: true *)\n decompress_response : bool; (* default: true *)\n\n (* Logging *)\n logger : Log.logger; (* default: Log.null *)\n}\n\nval default : config\nval with_timeout : float -\u003e config -\u003e config\nval with_max_connections : int -\u003e config -\u003e config\n(* ... other builders ... *)\n```\n\nPure configuration, no IO.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:05.431230385+01:00","updated_at":"2025-12-29T15:40:22.434194947+01:00","closed_at":"2025-12-29T15:40:22.434194947+01:00","dependencies":[{"issue_id":"hcs-9y1","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:42.307867928+01:00","created_by":"gdiazlo","metadata":"{}"}]} 60 + {"id":"hcs-9yc","title":"Go: Unified server with HTTP/1.1 + h2c + WebSocket","description":"Update Go net/http server to handle HTTP/1.1, h2c, and WebSocket on single port.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:36.193925748+01:00","updated_at":"2025-12-31T14:26:13.33110701+01:00","closed_at":"2025-12-31T14:26:13.33110701+01:00","dependencies":[{"issue_id":"hcs-9yc","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:30.935375958+01:00","created_by":"gdiazlo","metadata":"{}"}]} 61 + {"id":"hcs-a26","title":"Re-add auth to /events endpoint","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T19:58:30.99790983+01:00","updated_at":"2026-01-03T11:17:39.970701309+01:00","closed_at":"2026-01-03T11:17:39.970701309+01:00"} 62 + {"id":"hcs-ag6","title":"Implement H2 module (HTTP/2 specific features)","description":"Implement HTTP/2 specific features in hcs-eio/h2.ml:\n\n```ocaml\n(* Server push *)\nval push : request -\u003e Uri.t -\u003e (unit, error) result\n\n(* Stream priority *)\ntype priority = {\n dependency : int32;\n weight : int; (* 1-256 *)\n exclusive : bool;\n}\n\nval set_priority : priority -\u003e (unit, error) result\n\n(* Check protocol *)\nval is_h2 : request -\u003e bool\n```\n\nLower priority - can be added after basic HTTP/2 works.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-29T14:34:36.59579057+01:00","updated_at":"2025-12-29T17:39:24.986755909+01:00","closed_at":"2025-12-29T17:39:24.986755909+01:00","dependencies":[{"issue_id":"hcs-ag6","depends_on_id":"hcs-1uy","type":"parent-child","created_at":"2025-12-29T14:34:53.890566238+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-ag6","depends_on_id":"hcs-d5s","type":"blocks","created_at":"2025-12-29T14:34:58.997623679+01:00","created_by":"gdiazlo","metadata":"{}"}]} 63 + {"id":"hcs-ahy9","title":"docs: CORS recipe","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:59.219922605+01:00","updated_at":"2026-01-03T01:11:24.156380351+01:00","closed_at":"2026-01-03T01:11:24.156380351+01:00"} 64 + {"id":"hcs-ajc","title":"docs: Plugs Overview","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:44:43.504783964+01:00","updated_at":"2026-01-03T01:20:01.374029565+01:00","closed_at":"2026-01-03T01:20:01.374029565+01:00"} 65 + {"id":"hcs-ajr","title":"Compare HCS performance against external tools (wrk, hey)","description":"Validate HCS benchmark results by comparing against established tools:\n- Use wrk or hey to benchmark HCS server\n- Compare results with HCS benchmark client\n- Document any discrepancies\n- This validates both our server performance and benchmark accuracy\n\nOptional: Add script to run comparison benchmarks.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-29T18:04:05.806924896+01:00","updated_at":"2025-12-29T18:18:13.778810608+01:00","closed_at":"2025-12-29T18:18:13.778810608+01:00","dependencies":[{"issue_id":"hcs-ajr","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:25.893845517+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-ajr","depends_on_id":"hcs-4w8","type":"blocks","created_at":"2025-12-29T18:04:39.385790421+01:00","created_by":"gdiazlo","metadata":"{}"}]} 66 + {"id":"hcs-apjx","title":"docs: Error Handling guide","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T00:45:01.219350208+01:00","updated_at":"2026-01-03T01:20:01.381552365+01:00","closed_at":"2026-01-03T01:20:01.381552365+01:00"} 67 + {"id":"hcs-ax6","title":"Implement With_codec functor","description":"Implement the With_codec functor in hcs-core/codec.ml:\n\n```ocaml\nmodule With_codec (C : CODEC) : sig\n val encode_body : 'a C.encoder -\u003e 'a -\u003e (body, error) result\n val decode_body : 'a C.decoder -\u003e body -\u003e ('a, error) result\n\n (* Request helpers *)\n val set_body : 'a C.encoder -\u003e 'a -\u003e request -\u003e (request, error) result\n\n (* Response helpers *) \n val read_body : 'a C.decoder -\u003e response -\u003e ('a, error) result\n val make_response : ?status:status -\u003e 'a C.encoder -\u003e 'a -\u003e (response, error) result\nend\n```\n\nThe functor should:\n- Handle body type variants (Empty, Fixed, Stream, File)\n- Set appropriate Content-Type header from C.content_type\n- Convert between Cstruct.t and body types\n- Propagate codec errors as Codec_error\n\nPure OCaml, depends on types.ml and error.ml.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:28:47.94509919+01:00","updated_at":"2025-12-29T17:04:35.621002337+01:00","closed_at":"2025-12-29T17:04:35.621002337+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-ax6","depends_on_id":"hcs-m4r","type":"parent-child","created_at":"2025-12-29T14:29:00.595372107+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-ax6","depends_on_id":"hcs-pwc","type":"blocks","created_at":"2025-12-29T14:29:02.656963585+01:00","created_by":"gdiazlo","metadata":"{}"}]} 68 + {"id":"hcs-b83","title":"Implement Endpoint module","description":"Clean application bootstrap tying router, plugs, and server together.\n\n## Design\n\n### Core API\n```ocaml\nmodule Endpoint : sig\n type t\n type config = {\n port: int;\n bind: string;\n domains: int;\n secret_key_base: string;\n (* TLS, HTTP version, etc. *)\n }\n \n val create : config -\u003e t\n val plug : t -\u003e Plug.t -\u003e t\n val router : t -\u003e Router.t -\u003e t\n val start : t -\u003e env:Eio.Stdenv.t -\u003e unit\nend\n```\n\n### Usage\n```ocaml\nlet () =\n Endpoint.create config\n |\u003e Endpoint.plug (Plug.Logger.create ())\n |\u003e Endpoint.plug (Plug.Session.create ~store ())\n |\u003e Endpoint.plug (Plug.Csrf.create ())\n |\u003e Endpoint.router my_router\n |\u003e Endpoint.start ~env\n```\n\n### Features\n1. **Plug pipeline** - Ordered list of plugs applied to all requests\n2. **Router integration** - Final handler from router\n3. **Error handling** - Catch-all error responses\n4. **Graceful shutdown** - Handle SIGTERM/SIGINT\n5. **Health check** - Built-in /_health endpoint (optional)\n\n### Implementation\n- Composes plugs at startup (no runtime list traversal)\n- Passes config to plugs that need it (session secret, etc.)\n- Single Server.start call with composed handler\n\n### Performance\n- All composition happens at startup\n- Handler is a single function, no dynamic dispatch\n- Zero per-request allocation for endpoint logic","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:23.386314333+01:00","updated_at":"2026-01-01T21:30:28.400524063+01:00","closed_at":"2026-01-01T21:30:28.400524063+01:00","dependencies":[{"issue_id":"hcs-b83","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:48:06.720271707+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-b83","depends_on_id":"hcs-d0n","type":"blocks","created_at":"2026-01-01T20:48:16.796430672+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-b83","depends_on_id":"hcs-oqc","type":"blocks","created_at":"2026-01-01T20:48:21.832567305+01:00","created_by":"gdiazlo","metadata":"{}"}]} 69 + {"id":"hcs-bea","title":"Implement core middleware combinators","description":"Implement middleware composition in hcs-core/middleware.ml:\n\n```ocaml\ntype middleware = (request -\u003e (response, error) result) -\u003e request -\u003e (response, error) result\n\n(* Composition *)\nval ( @\u003e ) : middleware -\u003e middleware -\u003e middleware\nval compose : middleware list -\u003e middleware\nval identity : middleware\n\n(* Pure middleware (no IO needed) *)\nval default_headers : (string * string) list -\u003e middleware\nval catch_errors : (error -\u003e response) -\u003e middleware\nval body_limit : int64 -\u003e middleware\nval request_id : ?header:string -\u003e ?generator:(unit -\u003e string) -\u003e unit -\u003e middleware\n\n(* Security headers *)\nval security_headers : middleware\nval cors :\n ?origins:[ `All | `List of string list ] -\u003e\n ?methods:method_ list -\u003e\n ?headers:string list -\u003e\n ?max_age:int -\u003e\n ?credentials:bool -\u003e\n unit -\u003e\n middleware\n\n(* Auth - validation functions are pure *)\nval basic_auth : realm:string -\u003e validate:(user:string -\u003e pass:string -\u003e bool) -\u003e middleware\nval bearer_auth : validate:(token:string -\u003e bool) -\u003e middleware\n```\n\nPure OCaml.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:27.663177003+01:00","updated_at":"2025-12-29T15:18:06.262737908+01:00","closed_at":"2025-12-29T15:18:06.262737908+01:00","dependencies":[{"issue_id":"hcs-bea","depends_on_id":"hcs-3ww","type":"parent-child","created_at":"2025-12-29T14:34:50.365242865+01:00","created_by":"gdiazlo","metadata":"{}"}]} 70 + {"id":"hcs-cev","title":"Fix vote toggle logic in LAS - users can vote multiple times","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-02T21:39:23.222552566+01:00","updated_at":"2026-01-02T21:44:27.312031961+01:00","closed_at":"2026-01-02T21:44:27.312031961+01:00"} 71 + {"id":"hcs-cf24","title":"Refactor: Clean up Endpoint module","description":"Fix Endpoint to be purely the global plug layer:\n\n1. Remove server config (port, bind, domains, protocol, tls) \n2. Keep: secret_key_base, health_check (or make health a plug)\n3. Endpoint.start takes Server.config as parameter\n4. Endpoint is the global plug entry point before Router\n\n```ocaml\nlet endpoint =\n Endpoint.create { secret_key_base = \"...\"; health_check = true }\n |\u003e Endpoint.plug (Plug.Static.create ~path:\"/assets\" ())\n |\u003e Endpoint.plug (Plug.Request_id.create ())\n |\u003e Endpoint.plug (Plug.Session.create ~store ())\n |\u003e Endpoint.router router\n\nEndpoint.start endpoint ~server:Server.default_config ~env\n```","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:12:05.514288724+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:31:05.845237569+01:00","closed_at":"2026-01-03T21:31:05.845237569+01:00","close_reason":"Cleaned up Endpoint","dependencies":[{"issue_id":"hcs-cf24","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:12:59.612404272+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-cf24","depends_on_id":"hcs-uoki","type":"blocks","created_at":"2026-01-03T21:13:45.117182913+01:00","created_by":"gdiazlo"}]} 72 + {"id":"hcs-chm","title":"Implement body type","description":"Implement the body type in types.ml:\n- Empty variant\n- Fixed of string variant\n- Stream of (unit -\u003e Cstruct.t option) - pull-based streaming\n- File of string * int64 * int64 (path, offset, length)\n\nNote: The Stream variant uses a function type that is runtime-agnostic. For async streaming, we'll need a runtime-parameterized body type in the IO layer.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:16.560667848+01:00","updated_at":"2025-12-29T14:50:45.579783806+01:00","closed_at":"2025-12-29T14:50:45.579783806+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-chm","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:40.664331169+01:00","created_by":"gdiazlo","metadata":"{}"}]} 73 + {"id":"hcs-cks","title":"Implement Headers module","description":"Implement case-insensitive header map in headers.ml:\n- type t (backed by Map with lowercase keys)\n- empty, singleton, add, add_list\n- find, find_all, remove, mem\n- fold, to_list, of_list\n- Consider using a more efficient representation (e.g., sorted list for small headers)\n\nPure OCaml, no runtime dependency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:12.768404369+01:00","updated_at":"2025-12-29T14:50:44.414829218+01:00","closed_at":"2025-12-29T14:50:44.414829218+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-cks","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:39.839372964+01:00","created_by":"gdiazlo","metadata":"{}"}]} 74 + {"id":"hcs-cmg","title":"Implement version type","description":"Implement the HTTP version type:\n- HTTP_1_1, HTTP_2 variants\n- to_string/of_string functions\n\nPure OCaml, no runtime dependency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:10.081239709+01:00","updated_at":"2025-12-29T14:50:42.943845373+01:00","closed_at":"2025-12-29T14:50:42.943845373+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-cmg","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:39.140549859+01:00","created_by":"gdiazlo","metadata":"{}"}]} 51 75 {"id":"hcs-cq4","title":"HTTP/2 Server Performance Optimizations","description":"Implement optimizations identified from benchmarking: skip body reading for GET, optimize path extraction, reduce allocations","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-30T08:57:10.907204503+01:00","updated_at":"2025-12-30T09:02:03.611661211+01:00","closed_at":"2025-12-30T09:02:03.611661211+01:00"} 52 - {"id":"hcs-cwz","title":"Set up httpbin for client compliance testing","description":"Set up httpbin (or go-httpbin) for testing the HTTP client:\n\n1. Add Docker Compose file with go-httpbin service\n2. Create test suite covering:\n - All HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)\n - Request headers sent correctly\n - Query parameters encoding\n - Request body (form, JSON-like, binary)\n - Response status codes (1xx-5xx)\n - Redirects (301, 302, 303, 307, 308) with redirect limits\n - Basic auth, Bearer auth\n - Cookies (send and receive)\n - Compression (gzip, deflate)\n - Chunked transfer encoding\n - Connection keep-alive\n - Timeouts (delayed responses)\n - Large responses / streaming\n\n3. Integrate into `dune runtest` or separate compliance target","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:08.700591408+01:00","updated_at":"2025-12-29T17:56:36.02148206+01:00","closed_at":"2025-12-29T17:56:36.02148206+01:00","dependencies":[{"issue_id":"hcs-cwz","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:44.727305222+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-cwz","depends_on_id":"hcs-j2z","type":"blocks","created_at":"2025-12-29T14:36:54.844910505+01:00","created_by":"gdiazlo"}]} 53 - {"id":"hcs-cxj","title":"Add domain_count to server config","description":"Add domain_count field to H1_server.config and H2_server to specify max CPUs. Default to 1 for backward compatibility.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:52.544967921+01:00","updated_at":"2025-12-30T09:10:47.510063908+01:00","closed_at":"2025-12-30T09:10:47.510063908+01:00","dependencies":[{"issue_id":"hcs-cxj","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:14.106250303+01:00","created_by":"gdiazlo"}]} 54 - {"id":"hcs-cyb","title":"Implement Tls_config module","description":"Implement TLS configuration in hcs-core/tls_config.ml:\n\n```ocaml\ntype client\ntype server\n\ntype verification =\n | System_certificates\n | Custom_certificates of string list (* PEM file paths *)\n | Fingerprint of string\n | Insecure_no_verify\n\n(* Client config builder - returns config, actual TLS context created by runtime *)\nval client :\n ?verification:verification -\u003e\n ?alpn_protocols:string list -\u003e\n ?hostname:string -\u003e\n unit -\u003e\n client\n\n(* Server config builder *)\nval server :\n cert_file:string -\u003e\n key_file:string -\u003e\n ?alpn_protocols:string list -\u003e\n ?client_auth:[ `None | `Optional | `Required ] -\u003e\n ?ca_file:string -\u003e\n unit -\u003e\n server\n```\n\nThe actual TLS context creation (using tls-eio or tls-lwt) happens in the runtime layer. This module just holds configuration.\n\nPure OCaml, configuration types only.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:30:31.480806804+01:00","updated_at":"2025-12-29T15:24:40.571579433+01:00","closed_at":"2025-12-29T15:24:40.571579433+01:00","dependencies":[{"issue_id":"hcs-cyb","depends_on_id":"hcs-y9w","type":"parent-child","created_at":"2025-12-29T14:30:46.125231092+01:00","created_by":"gdiazlo"}]} 55 - {"id":"hcs-cyk","title":"Implement unified Server module (Eio)","description":"Implement unified server API in hcs-eio/server.ml:\n\n```ocaml\ntype t\n\nval create :\n sw:Eio.Switch.t -\u003e\n net:Eio.Net.t -\u003e\n clock:Eio.Time.clock -\u003e\n ?config:config -\u003e\n Router.compiled -\u003e\n t\n\nval run : t -\u003e unit (* Blocks until shutdown *)\nval shutdown : ?timeout:float -\u003e t -\u003e unit\nval listening_on : t -\u003e (string * int)\nval connection_count : t -\u003e int\n```\n\nFeatures:\n- Accept connections, spawn fibers\n- Protocol detection (ALPN for TLS, prior knowledge)\n- Dispatch to H1 or H2 handler\n- Connection limiting\n- Graceful shutdown with drain timeout\n- TLS support","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:29.304626659+01:00","updated_at":"2025-12-29T17:00:22.652965066+01:00","closed_at":"2025-12-29T17:00:22.652965066+01:00","dependencies":[{"issue_id":"hcs-cyk","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:43.591242696+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-lqi","type":"blocks","created_at":"2025-12-29T14:33:45.174337222+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-1vt","type":"blocks","created_at":"2025-12-29T14:33:46.071365575+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-sny","type":"blocks","created_at":"2025-12-29T14:33:46.914541815+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-2ca","type":"blocks","created_at":"2025-12-29T14:33:47.760104216+01:00","created_by":"gdiazlo"}]} 56 - {"id":"hcs-czm","title":"Streaming Abstraction","description":"Implement the Stream module with producers, transformers, consumers, and combinators for lazy, backpressure-aware streaming.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:20.968837055+01:00","updated_at":"2025-12-29T17:41:32.374046501+01:00","closed_at":"2025-12-29T17:41:32.374046501+01:00","dependencies":[{"issue_id":"hcs-czm","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:25:57.77315075+01:00","created_by":"gdiazlo"}]} 57 - {"id":"hcs-d0n","title":"Implement Sessions plug","description":"Cookie-based session management with pluggable storage backends.\n\n## Design\n\n### Core Types\n```ocaml\ntype session = {\n id: string;\n data: (string * string) list; (* Avoid Map allocation for small sessions *)\n created_at: float;\n modified: bool;\n}\n\ntype store = {\n get: string -\u003e session option;\n put: session -\u003e unit;\n delete: string -\u003e unit;\n}\n```\n\n### Storage Backends\n1. **Memory store** - Hashtbl with optional TTL cleanup (dev/testing)\n2. **Cookie store** - Entire session encrypted in cookie (no server state)\n3. **ETS-like store** - For future distributed sessions\n\n### Plug Implementation\n- `Session.create ~store ~secret ~cookie_name () : Plug.t`\n- Reads session cookie on request, injects into request context\n- Writes session cookie on response if modified\n- Uses AEAD encryption (existing crypto deps) for cookie store\n\n### API for Handlers\n```ocaml\nval get : request -\u003e string -\u003e string option\nval put : request -\u003e string -\u003e string -\u003e request \nval delete : request -\u003e string -\u003e request\nval clear : request -\u003e request\n```\n\n### Performance\n- Lazy session loading (don't decrypt until accessed)\n- Reuse session ID across requests\n- Minimal allocations: parse cookie once, store as list not Map","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:46:56.94254581+01:00","updated_at":"2026-01-01T21:25:06.957911127+01:00","closed_at":"2026-01-01T21:25:06.957911127+01:00","dependencies":[{"issue_id":"hcs-d0n","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:47:51.607587044+01:00","created_by":"gdiazlo"}]} 58 - {"id":"hcs-d3q","title":"Set up Autobahn for WebSocket compliance testing","description":"Integrate Autobahn|Testsuite for WebSocket compliance:\n\n1. Add Autobahn to CI via Docker (crossbario/autobahn-testsuite)\n2. Test both client and server modes:\n\n**Server testing** (Autobahn as client):\n```\ndocker run -it --rm \\\n -v \"${PWD}/reports:/reports\" \\\n crossbario/autobahn-testsuite \\\n wstest -m fuzzingclient -s /config/fuzzingclient.json\n```\n\n**Client testing** (Autobahn as server):\n```\ndocker run -it --rm \\\n -v \"${PWD}/reports:/reports\" \\\n crossbario/autobahn-testsuite \\\n wstest -m fuzzingserver -s /config/fuzzingserver.json\n```\n\nTest cases cover:\n- Framing (text, binary, fragmentation)\n- Ping/Pong\n- Close handshake\n- Reserved bits\n- Opcodes\n- UTF-8 validation\n- Compression (permessage-deflate)\n- Limits and performance\n\nTarget: Pass all non-optional Autobahn test cases","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:18.251422099+01:00","updated_at":"2025-12-29T17:57:13.521624023+01:00","closed_at":"2025-12-29T17:57:13.521624023+01:00","dependencies":[{"issue_id":"hcs-d3q","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:48.059495592+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-d3q","depends_on_id":"hcs-nad","type":"blocks","created_at":"2025-12-29T14:36:58.909180795+01:00","created_by":"gdiazlo"}]} 59 - {"id":"hcs-d5s","title":"Implement HTTP/2 client (Eio)","description":"Implement HTTP/2 client for Eio in hcs-eio/h2_client.ml:\n\n```ocaml\ntype t (* HTTP/2 connection with multiplexed streams *)\n\nval create : flow:Eio.Flow.two_way -\u003e clock:Eio.Time.clock -\u003e config:Client.config -\u003e t\nval request : t -\u003e ?cancel:Cancel.t -\u003e request -\u003e (response, error) result\nval close : t -\u003e unit\n```\n\nFeatures:\n- HPACK header compression\n- Stream multiplexing\n- Flow control per stream and connection\n- SETTINGS frame handling\n- Priority hints (optional)\n- GOAWAY handling\n\nDepends on hpack package.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:31:23.240487001+01:00","updated_at":"2025-12-29T16:00:40.891022027+01:00","closed_at":"2025-12-29T16:00:40.891022027+01:00","dependencies":[{"issue_id":"hcs-d5s","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:50.019661778+01:00","created_by":"gdiazlo"}]} 60 - {"id":"hcs-d9v","title":"Add retry middleware to middleware_eio.ml","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:15:15.977235935+01:00","updated_at":"2026-01-01T18:16:24.78563205+01:00","closed_at":"2026-01-01T18:16:24.78563205+01:00"} 61 - {"id":"hcs-dd4","title":"Set up h2spec for HTTP/2 compliance testing","description":"Integrate h2spec for HTTP/2 server compliance:\n\n1. Add h2spec to CI (available as binary or Docker)\n2. Create test harness that:\n - Starts hcs HTTP/2 server on test port\n - Runs h2spec against it\n - Parses results\n\nh2spec tests:\n- HPACK header compression\n- Stream states and transitions\n- Flow control (window updates)\n- Error handling (RST_STREAM, GOAWAY)\n- SETTINGS frames\n- PRIORITY frames\n- CONTINUATION frames\n- Frame size limits\n- Connection preface\n\nTarget: Pass all h2spec generic tests\n\nCommand: `h2spec -h localhost -p 8080 --strict`","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:13.071332042+01:00","updated_at":"2025-12-29T17:57:10.493059681+01:00","closed_at":"2025-12-29T17:57:10.493059681+01:00","dependencies":[{"issue_id":"hcs-dd4","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:46.491278695+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-dd4","depends_on_id":"hcs-cyk","type":"blocks","created_at":"2025-12-29T14:36:57.517342388+01:00","created_by":"gdiazlo"}]} 62 - {"id":"hcs-ddd","title":"Create HTTP/2 cross-language benchmark script","description":"Create run_h2_comparison.sh that starts all three servers (HCS, Rust, Go) and runs h2load benchmarks against each. Test /ping, /bytes/1024, /bytes/10240 endpoints. Output structured results for comparison.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T08:21:57.169092148+01:00","updated_at":"2025-12-30T08:48:51.028339202+01:00","closed_at":"2025-12-30T08:48:51.028339202+01:00","dependencies":[{"issue_id":"hcs-ddd","depends_on_id":"hcs-osg","type":"blocks","created_at":"2025-12-30T08:22:14.06532517+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-ddd","depends_on_id":"hcs-l9p","type":"blocks","created_at":"2025-12-30T08:22:16.71293984+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-ddd","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:25.823611037+01:00","created_by":"gdiazlo"}]} 63 - {"id":"hcs-dle","title":"Request/Response Helpers","description":"Implement Request and Response helper modules with body handling, status shortcuts, and codec integration.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:33.481216228+01:00","updated_at":"2025-12-29T15:40:53.163093449+01:00","closed_at":"2025-12-29T15:40:53.163093449+01:00","dependencies":[{"issue_id":"hcs-dle","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:17.959259297+01:00","created_by":"gdiazlo"}]} 64 - {"id":"hcs-dpu","title":"LAS: Project setup (dune, dependencies)","description":"Create bin/las/dune with libraries: hcs, caqti, caqti-driver-sqlite3, caqti-eio, yojson. Set up executable definition.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:22.138827845+01:00","updated_at":"2026-01-01T23:49:20.337195774+01:00","closed_at":"2026-01-01T23:49:20.337195774+01:00","dependencies":[{"issue_id":"hcs-dpu","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:18.213570142+01:00","created_by":"gdiazlo"}]} 65 - {"id":"hcs-dsf","title":"Set up project structure and dune build","description":"Set up the OCaml project structure with dune:\n\n```\nhcs/\n├── dune-project\n├── hcs-core/ # Pure, runtime-agnostic\n│ ├── dune\n│ ├── types.ml\n│ ├── error.ml\n│ ├── headers.ml\n│ ├── stream.ml # Synchronous stream operations\n│ ├── codec.ml\n│ └── hcs_core.ml # Public API re-exports\n├── hcs-eio/ # Eio runtime\n│ ├── dune\n│ ├── runtime.ml # RUNTIME implementation for Eio\n│ ├── client.ml\n│ ├── server.ml\n│ └── hcs_eio.ml\n└── hcs/ # Convenience package (re-exports hcs-eio)\n ├── dune\n └── hcs.ml\n```\n\nConfigure opam dependencies.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:26.717322855+01:00","updated_at":"2025-12-29T14:50:39.789609025+01:00","closed_at":"2025-12-29T14:50:39.789609025+01:00","labels":["infrastructure"],"dependencies":[{"issue_id":"hcs-dsf","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:43.02614445+01:00","created_by":"gdiazlo"}]} 66 - {"id":"hcs-dzr","title":"Create TechEmpower-style benchmark suite with hyper, fasthttp, and HCS servers","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-30T22:21:05.455078159+01:00","updated_at":"2025-12-30T22:33:15.399922114+01:00","closed_at":"2025-12-30T22:33:15.399922114+01:00"} 67 - {"id":"hcs-ez2","title":"Implement Content Negotiation","description":"Parse Accept headers and select response format.\n\n## Design\n\n### Core Types\n```ocaml\ntype media_type = {\n type_: string; (* e.g., \"application\" *)\n subtype: string; (* e.g., \"json\" *)\n quality: float; (* 0.0 - 1.0 *)\n params: (string * string) list;\n}\n\ntype format = Json | Html | Text | Xml | Custom of string\n```\n\n### Parser\n```ocaml\nval parse_accept : string -\u003e media_type list\n(* Returns sorted by quality, highest first *)\n```\n\n### Negotiation\n```ocaml\nval negotiate : accept:string -\u003e available:format list -\u003e format option\n(* Returns best match or None *)\n\nval negotiate_exn : accept:string -\u003e available:format list -\u003e format\n(* Returns best match or raises Not_acceptable *)\n```\n\n### Plug Integration\n```ocaml\nmodule Plug.Negotiate : sig\n val create : formats:format list -\u003e Plug.t\n (* Sets negotiated format in request, returns 406 if no match *)\nend\n\nval get_format : request -\u003e format option\n```\n\n### Response Helpers\n```ocaml\nval respond_format : format -\u003e body:string -\u003e response\n(* Sets correct Content-Type *)\n\nval respond_negotiate : request -\u003e \n json:(unit -\u003e string) -\u003e \n html:(unit -\u003e string) -\u003e \n response\n(* Lazy evaluation - only runs the selected format *)\n```\n\n### Performance\n- Single-pass parser, no regex\n- Pre-sorted available formats by preference\n- Lazy body generation (no allocation until format selected)","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:14.119965918+01:00","updated_at":"2026-01-01T21:01:33.869936139+01:00","closed_at":"2026-01-01T21:01:33.869936139+01:00","dependencies":[{"issue_id":"hcs-ez2","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:48:01.682801946+01:00","created_by":"gdiazlo"}]} 68 - {"id":"hcs-f2r","title":"Skip body reading for bodiless methods (GET/HEAD/DELETE)","description":"In h2_server.ml, skip Buffer.create, Promise.create, and body reading for GET/HEAD/DELETE methods. These have no body but currently allocate a buffer and promise.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:57:23.954431824+01:00","updated_at":"2025-12-30T09:01:38.714453571+01:00","closed_at":"2025-12-30T09:01:38.714453571+01:00","dependencies":[{"issue_id":"hcs-f2r","depends_on_id":"hcs-cq4","type":"parent-child","created_at":"2025-12-30T08:57:44.799141738+01:00","created_by":"gdiazlo"}]} 69 - {"id":"hcs-fgd","title":"Logging System","description":"Implement Log module with level, event types, built-in loggers (null, stderr, custom), and event formatting.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:26.517303879+01:00","updated_at":"2025-12-29T17:40:48.765669075+01:00","closed_at":"2025-12-29T17:40:48.765669075+01:00","dependencies":[{"issue_id":"hcs-fgd","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:08.827592455+01:00","created_by":"gdiazlo"}]} 70 - {"id":"hcs-fsc","title":"Implement Request helper module","description":"Implement request helpers in hcs-core/request.ml:\n\n```ocaml\nval path : request -\u003e string\nval query : string -\u003e request -\u003e string option\nval query_all : string -\u003e request -\u003e string list\nval header : string -\u003e request -\u003e string option\nval header_all : string -\u003e request -\u003e string list\nval content_type : request -\u003e string option\nval content_length : request -\u003e int64 option\nval is_keep_alive : request -\u003e bool\n\n(* Body consumption - sync versions *)\nval body_string : request -\u003e (string, error) result\nval body_to_cstruct : request -\u003e (Cstruct.t, error) result\n\n(* Form data parsing *)\nval form : request -\u003e ((string * string) list, error) result\n```\n\nPure OCaml + uri package.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:34:09.842512086+01:00","updated_at":"2025-12-29T15:40:29.136273489+01:00","closed_at":"2025-12-29T15:40:29.136273489+01:00","dependencies":[{"issue_id":"hcs-fsc","depends_on_id":"hcs-dle","type":"parent-child","created_at":"2025-12-29T14:34:47.838799048+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-fsc","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:34:54.851316989+01:00","created_by":"gdiazlo"}]} 71 - {"id":"hcs-g2y","title":"Research HTTP compliance test suites","description":"Research and document available HTTP compliance testing tools and servers:\n\n**For Client Testing (test servers):**\n\n1. **httpbin** (https://httpbin.org / kennethreitz/httpbin)\n - Returns request info as JSON\n - Tests: methods, headers, redirects, auth, cookies, response codes\n - Can run locally via Docker\n\n2. **go-httpbin** (mccutchen/go-httpbin)\n - Go reimplementation, faster and more features\n - Better for local testing\n\n3. **h2spec** (summerwind/h2spec)\n - HTTP/2 conformance testing tool\n - Tests HPACK, streams, flow control, error handling\n - Essential for HTTP/2 compliance\n\n4. **curl test suite**\n - curl's own test servers have extensive edge cases\n\n**For Server Testing (test clients):**\n\n1. **h2load** (nghttp2)\n - HTTP/2 benchmarking and testing\n - Tests multiplexing, flow control\n\n2. **curl** with verbose options\n - Good for basic HTTP/1.1 compliance\n\n3. **nghttp** (nghttp2)\n - HTTP/2 client for testing server responses\n\n4. **Autobahn|Testsuite** (for WebSocket)\n - Comprehensive WebSocket protocol compliance\n - https://github.com/crossbario/autobahn-testsuite\n\n**RFC Compliance:**\n- RFC 7230-7235 (HTTP/1.1)\n- RFC 7540 (HTTP/2)\n- RFC 6455 (WebSocket)\n- RFC 7541 (HPACK)\n\nEvaluate which tools to integrate into CI.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:36:03.601972706+01:00","updated_at":"2025-12-29T17:31:46.947022974+01:00","closed_at":"2025-12-29T17:31:46.947022974+01:00","dependencies":[{"issue_id":"hcs-g2y","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:42.697870585+01:00","created_by":"gdiazlo"}]} 72 - {"id":"hcs-g40","title":"Update test/dune with mirage-crypto-rng dependency","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:16:47.415817521+01:00","updated_at":"2026-01-01T22:20:00.598342536+01:00","closed_at":"2026-01-01T22:20:00.598342536+01:00","dependencies":[{"issue_id":"hcs-g40","depends_on_id":"hcs-6t7","type":"blocks","created_at":"2026-01-01T22:17:01.18997103+01:00","created_by":"gdiazlo"}]} 73 - {"id":"hcs-gii","title":"LAS: Database layer (db.ml)","description":"Caqti connection pool, schema initialization, queries for links/users/votes/comments. Use SQLite.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:32.219826186+01:00","updated_at":"2026-01-01T23:55:18.482315084+01:00","closed_at":"2026-01-01T23:55:18.482315084+01:00","dependencies":[{"issue_id":"hcs-gii","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:28.299766704+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-gii","depends_on_id":"hcs-y5a","type":"blocks","created_at":"2026-01-01T23:43:08.598843871+01:00","created_by":"gdiazlo"}]} 74 - {"id":"hcs-gmb","title":"Implement error type","description":"Implement comprehensive error type in error.ml:\n- Connection_failed, Connection_closed\n- Timeout variants (Connect, Read, Write, Total)\n- Cancelled\n- Invalid_url, Invalid_response\n- Too_many_redirects\n- Protocol_error, Tls_error, Codec_error\n- Body_too_large, IO_error\n\nInclude to_string for debugging. Pure OCaml.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:22.136715155+01:00","updated_at":"2025-12-29T14:50:40.75088559+01:00","closed_at":"2025-12-29T14:50:40.75088559+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-gmb","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:42.239579889+01:00","created_by":"gdiazlo"}]} 75 - {"id":"hcs-gr3","title":"Implement gzip and zstd compression/decompression functions","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:16.145810916+01:00","updated_at":"2026-01-01T18:47:23.516801771+01:00","closed_at":"2026-01-01T18:47:23.516801771+01:00","dependencies":[{"issue_id":"hcs-gr3","depends_on_id":"hcs-ro3","type":"blocks","created_at":"2026-01-01T18:44:41.614944047+01:00","created_by":"gdiazlo"}]} 76 - {"id":"hcs-h2a","title":"Benchmark runner script with memory profiling","description":"Create benchmark runner that tests all servers across all protocols, measures req/s, msg/s, memory/connection, and produces summary report.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-31T14:13:51.31059033+01:00","updated_at":"2025-12-31T14:47:32.444742919+01:00","closed_at":"2025-12-31T14:47:32.444742919+01:00","dependencies":[{"issue_id":"hcs-h2a","depends_on_id":"hcs-rzc","type":"blocks","created_at":"2025-12-31T14:14:05.717334469+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-9yc","type":"blocks","created_at":"2025-12-31T14:14:10.761462149+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-s94","type":"blocks","created_at":"2025-12-31T14:14:15.805316293+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-peu","type":"blocks","created_at":"2025-12-31T14:14:20.849391195+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:46.066127034+01:00","created_by":"gdiazlo"}]} 77 - {"id":"hcs-h2u","title":"Add circuit_breaker middleware to middleware_eio.ml","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:15:15.277426489+01:00","updated_at":"2026-01-01T18:16:24.778681979+01:00","closed_at":"2026-01-01T18:16:24.778681979+01:00"} 78 - {"id":"hcs-hkf","title":"Add benchmark runner script with standard scenarios","description":"Create a benchmark runner script (bench/run_benchmarks.sh) that runs standard benchmark scenarios:\n1. Minimal GET (/ping) - pure overhead measurement\n2. Small payload (1KB) - typical API response\n3. Medium payload (10KB) - larger JSON responses \n4. Large payload (100KB) - file downloads\n5. POST with body - request body handling\n6. Varying concurrency (1, 10, 50, 100, 200 connections)\n7. HTTP/1.1 vs HTTP/2 comparison\n\nOutput results to bench/results/ with timestamps for tracking over time.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T18:04:02.294539956+01:00","updated_at":"2025-12-29T18:17:10.742622288+01:00","closed_at":"2025-12-29T18:17:10.742622288+01:00","dependencies":[{"issue_id":"hcs-hkf","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:24.660841757+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-hkf","depends_on_id":"hcs-4w8","type":"blocks","created_at":"2025-12-29T18:04:36.967445707+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-hkf","depends_on_id":"hcs-320","type":"blocks","created_at":"2025-12-29T18:04:38.425355179+01:00","created_by":"gdiazlo"}]} 79 - {"id":"hcs-i4f","title":"Setup bench/ directory structure with .gitignore","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:21.51511238+01:00","updated_at":"2025-12-30T22:23:03.029513364+01:00","closed_at":"2025-12-30T22:23:03.029513364+01:00"} 80 - {"id":"hcs-i8j","title":"Implement OCaml/HCS benchmark server (plaintext + json, HTTP/1+2, CPU scaling)","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:36.638072425+01:00","updated_at":"2025-12-30T22:28:28.339092129+01:00","closed_at":"2025-12-30T22:28:28.339092129+01:00"} 81 - {"id":"hcs-j2z","title":"Implement unified Client module (Eio)","description":"Implement unified client API in hcs-eio/client.ml:\n\n```ocaml\ntype t\n\nval create :\n sw:Eio.Switch.t -\u003e\n net:Eio.Net.t -\u003e\n clock:Eio.Time.clock -\u003e\n ?config:config -\u003e\n unit -\u003e\n t\n\nval request : ?cancel:Cancel.t -\u003e t -\u003e request -\u003e (response, error) result\nval fetch : ?cancel:Cancel.t -\u003e t -\u003e request -\u003e (status * Headers.t * string, error) result\nval stream : ?cancel:Cancel.t -\u003e t -\u003e request -\u003e (status * Headers.t * Cstruct.t Stream.t, error) result\n\nval close_idle : t -\u003e unit\nval pool_stats : t -\u003e { active: int; idle: int; total: int }\n```\n\nFeatures:\n- Protocol selection (HTTP/1.1 vs HTTP/2) via ALPN or config\n- Connection pooling\n- Automatic redirect following\n- Compression handling\n- TLS with system certs by default","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:27.67982735+01:00","updated_at":"2025-12-29T17:00:20.730823454+01:00","closed_at":"2025-12-29T17:00:20.730823454+01:00","dependencies":[{"issue_id":"hcs-j2z","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:51.749045471+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-j2z","depends_on_id":"hcs-7n9","type":"blocks","created_at":"2025-12-29T14:31:54.365652586+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-j2z","depends_on_id":"hcs-d5s","type":"blocks","created_at":"2025-12-29T14:31:55.246269371+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-j2z","depends_on_id":"hcs-2ca","type":"blocks","created_at":"2025-12-29T14:31:55.835151512+01:00","created_by":"gdiazlo"}]} 82 - {"id":"hcs-j5q","title":"Move Go benchmark server to dedicated folder (bench/comparison/go_fasthttp/)","description":"","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-12-30T00:14:15.760072799+01:00","updated_at":"2025-12-30T00:17:18.571463212+01:00","closed_at":"2025-12-30T00:17:18.571463212+01:00"} 83 - {"id":"hcs-j7j","title":"Implement Go/fasthttp benchmark server (plaintext + json, HTTP/1+2, CPU scaling)","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:31.597229058+01:00","updated_at":"2025-12-30T22:28:28.338758567+01:00","closed_at":"2025-12-30T22:28:28.338758567+01:00"} 76 + {"id":"hcs-cwz","title":"Set up httpbin for client compliance testing","description":"Set up httpbin (or go-httpbin) for testing the HTTP client:\n\n1. Add Docker Compose file with go-httpbin service\n2. Create test suite covering:\n - All HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)\n - Request headers sent correctly\n - Query parameters encoding\n - Request body (form, JSON-like, binary)\n - Response status codes (1xx-5xx)\n - Redirects (301, 302, 303, 307, 308) with redirect limits\n - Basic auth, Bearer auth\n - Cookies (send and receive)\n - Compression (gzip, deflate)\n - Chunked transfer encoding\n - Connection keep-alive\n - Timeouts (delayed responses)\n - Large responses / streaming\n\n3. Integrate into `dune runtest` or separate compliance target","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:08.700591408+01:00","updated_at":"2025-12-29T17:56:36.02148206+01:00","closed_at":"2025-12-29T17:56:36.02148206+01:00","dependencies":[{"issue_id":"hcs-cwz","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:44.727305222+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-cwz","depends_on_id":"hcs-j2z","type":"blocks","created_at":"2025-12-29T14:36:54.844910505+01:00","created_by":"gdiazlo","metadata":"{}"}]} 77 + {"id":"hcs-cxj","title":"Add domain_count to server config","description":"Add domain_count field to H1_server.config and H2_server to specify max CPUs. Default to 1 for backward compatibility.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:52.544967921+01:00","updated_at":"2025-12-30T09:10:47.510063908+01:00","closed_at":"2025-12-30T09:10:47.510063908+01:00","dependencies":[{"issue_id":"hcs-cxj","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:14.106250303+01:00","created_by":"gdiazlo","metadata":"{}"}]} 78 + {"id":"hcs-cyb","title":"Implement Tls_config module","description":"Implement TLS configuration in hcs-core/tls_config.ml:\n\n```ocaml\ntype client\ntype server\n\ntype verification =\n | System_certificates\n | Custom_certificates of string list (* PEM file paths *)\n | Fingerprint of string\n | Insecure_no_verify\n\n(* Client config builder - returns config, actual TLS context created by runtime *)\nval client :\n ?verification:verification -\u003e\n ?alpn_protocols:string list -\u003e\n ?hostname:string -\u003e\n unit -\u003e\n client\n\n(* Server config builder *)\nval server :\n cert_file:string -\u003e\n key_file:string -\u003e\n ?alpn_protocols:string list -\u003e\n ?client_auth:[ `None | `Optional | `Required ] -\u003e\n ?ca_file:string -\u003e\n unit -\u003e\n server\n```\n\nThe actual TLS context creation (using tls-eio or tls-lwt) happens in the runtime layer. This module just holds configuration.\n\nPure OCaml, configuration types only.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:30:31.480806804+01:00","updated_at":"2025-12-29T15:24:40.571579433+01:00","closed_at":"2025-12-29T15:24:40.571579433+01:00","dependencies":[{"issue_id":"hcs-cyb","depends_on_id":"hcs-y9w","type":"parent-child","created_at":"2025-12-29T14:30:46.125231092+01:00","created_by":"gdiazlo","metadata":"{}"}]} 79 + {"id":"hcs-cyk","title":"Implement unified Server module (Eio)","description":"Implement unified server API in hcs-eio/server.ml:\n\n```ocaml\ntype t\n\nval create :\n sw:Eio.Switch.t -\u003e\n net:Eio.Net.t -\u003e\n clock:Eio.Time.clock -\u003e\n ?config:config -\u003e\n Router.compiled -\u003e\n t\n\nval run : t -\u003e unit (* Blocks until shutdown *)\nval shutdown : ?timeout:float -\u003e t -\u003e unit\nval listening_on : t -\u003e (string * int)\nval connection_count : t -\u003e int\n```\n\nFeatures:\n- Accept connections, spawn fibers\n- Protocol detection (ALPN for TLS, prior knowledge)\n- Dispatch to H1 or H2 handler\n- Connection limiting\n- Graceful shutdown with drain timeout\n- TLS support","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:29.304626659+01:00","updated_at":"2025-12-29T17:00:22.652965066+01:00","closed_at":"2025-12-29T17:00:22.652965066+01:00","dependencies":[{"issue_id":"hcs-cyk","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:43.591242696+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-lqi","type":"blocks","created_at":"2025-12-29T14:33:45.174337222+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-1vt","type":"blocks","created_at":"2025-12-29T14:33:46.071365575+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-sny","type":"blocks","created_at":"2025-12-29T14:33:46.914541815+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-cyk","depends_on_id":"hcs-2ca","type":"blocks","created_at":"2025-12-29T14:33:47.760104216+01:00","created_by":"gdiazlo","metadata":"{}"}]} 80 + {"id":"hcs-czm","title":"Streaming Abstraction","description":"Implement the Stream module with producers, transformers, consumers, and combinators for lazy, backpressure-aware streaming.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:20.968837055+01:00","updated_at":"2025-12-29T17:41:32.374046501+01:00","closed_at":"2025-12-29T17:41:32.374046501+01:00","dependencies":[{"issue_id":"hcs-czm","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:25:57.77315075+01:00","created_by":"gdiazlo","metadata":"{}"}]} 81 + {"id":"hcs-d0n","title":"Implement Sessions plug","description":"Cookie-based session management with pluggable storage backends.\n\n## Design\n\n### Core Types\n```ocaml\ntype session = {\n id: string;\n data: (string * string) list; (* Avoid Map allocation for small sessions *)\n created_at: float;\n modified: bool;\n}\n\ntype store = {\n get: string -\u003e session option;\n put: session -\u003e unit;\n delete: string -\u003e unit;\n}\n```\n\n### Storage Backends\n1. **Memory store** - Hashtbl with optional TTL cleanup (dev/testing)\n2. **Cookie store** - Entire session encrypted in cookie (no server state)\n3. **ETS-like store** - For future distributed sessions\n\n### Plug Implementation\n- `Session.create ~store ~secret ~cookie_name () : Plug.t`\n- Reads session cookie on request, injects into request context\n- Writes session cookie on response if modified\n- Uses AEAD encryption (existing crypto deps) for cookie store\n\n### API for Handlers\n```ocaml\nval get : request -\u003e string -\u003e string option\nval put : request -\u003e string -\u003e string -\u003e request \nval delete : request -\u003e string -\u003e request\nval clear : request -\u003e request\n```\n\n### Performance\n- Lazy session loading (don't decrypt until accessed)\n- Reuse session ID across requests\n- Minimal allocations: parse cookie once, store as list not Map","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:46:56.94254581+01:00","updated_at":"2026-01-01T21:25:06.957911127+01:00","closed_at":"2026-01-01T21:25:06.957911127+01:00","dependencies":[{"issue_id":"hcs-d0n","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:47:51.607587044+01:00","created_by":"gdiazlo","metadata":"{}"}]} 82 + {"id":"hcs-d3q","title":"Set up Autobahn for WebSocket compliance testing","description":"Integrate Autobahn|Testsuite for WebSocket compliance:\n\n1. Add Autobahn to CI via Docker (crossbario/autobahn-testsuite)\n2. Test both client and server modes:\n\n**Server testing** (Autobahn as client):\n```\ndocker run -it --rm \\\n -v \"${PWD}/reports:/reports\" \\\n crossbario/autobahn-testsuite \\\n wstest -m fuzzingclient -s /config/fuzzingclient.json\n```\n\n**Client testing** (Autobahn as server):\n```\ndocker run -it --rm \\\n -v \"${PWD}/reports:/reports\" \\\n crossbario/autobahn-testsuite \\\n wstest -m fuzzingserver -s /config/fuzzingserver.json\n```\n\nTest cases cover:\n- Framing (text, binary, fragmentation)\n- Ping/Pong\n- Close handshake\n- Reserved bits\n- Opcodes\n- UTF-8 validation\n- Compression (permessage-deflate)\n- Limits and performance\n\nTarget: Pass all non-optional Autobahn test cases","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:18.251422099+01:00","updated_at":"2025-12-29T17:57:13.521624023+01:00","closed_at":"2025-12-29T17:57:13.521624023+01:00","dependencies":[{"issue_id":"hcs-d3q","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:48.059495592+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-d3q","depends_on_id":"hcs-nad","type":"blocks","created_at":"2025-12-29T14:36:58.909180795+01:00","created_by":"gdiazlo","metadata":"{}"}]} 83 + {"id":"hcs-d5s","title":"Implement HTTP/2 client (Eio)","description":"Implement HTTP/2 client for Eio in hcs-eio/h2_client.ml:\n\n```ocaml\ntype t (* HTTP/2 connection with multiplexed streams *)\n\nval create : flow:Eio.Flow.two_way -\u003e clock:Eio.Time.clock -\u003e config:Client.config -\u003e t\nval request : t -\u003e ?cancel:Cancel.t -\u003e request -\u003e (response, error) result\nval close : t -\u003e unit\n```\n\nFeatures:\n- HPACK header compression\n- Stream multiplexing\n- Flow control per stream and connection\n- SETTINGS frame handling\n- Priority hints (optional)\n- GOAWAY handling\n\nDepends on hpack package.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:31:23.240487001+01:00","updated_at":"2025-12-29T16:00:40.891022027+01:00","closed_at":"2025-12-29T16:00:40.891022027+01:00","dependencies":[{"issue_id":"hcs-d5s","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:50.019661778+01:00","created_by":"gdiazlo","metadata":"{}"}]} 84 + {"id":"hcs-d76","title":"docs: HTTP Client Basic Requests guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:51.972055552+01:00","updated_at":"2026-01-03T01:20:01.381822576+01:00","closed_at":"2026-01-03T01:20:01.381822576+01:00"} 85 + {"id":"hcs-d9v","title":"Add retry middleware to middleware_eio.ml","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:15:15.977235935+01:00","updated_at":"2026-01-01T18:16:24.78563205+01:00","closed_at":"2026-01-01T18:16:24.78563205+01:00"} 86 + {"id":"hcs-dd4","title":"Set up h2spec for HTTP/2 compliance testing","description":"Integrate h2spec for HTTP/2 server compliance:\n\n1. Add h2spec to CI (available as binary or Docker)\n2. Create test harness that:\n - Starts hcs HTTP/2 server on test port\n - Runs h2spec against it\n - Parses results\n\nh2spec tests:\n- HPACK header compression\n- Stream states and transitions\n- Flow control (window updates)\n- Error handling (RST_STREAM, GOAWAY)\n- SETTINGS frames\n- PRIORITY frames\n- CONTINUATION frames\n- Frame size limits\n- Connection preface\n\nTarget: Pass all h2spec generic tests\n\nCommand: `h2spec -h localhost -p 8080 --strict`","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:13.071332042+01:00","updated_at":"2025-12-29T17:57:10.493059681+01:00","closed_at":"2025-12-29T17:57:10.493059681+01:00","dependencies":[{"issue_id":"hcs-dd4","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:46.491278695+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-dd4","depends_on_id":"hcs-cyk","type":"blocks","created_at":"2025-12-29T14:36:57.517342388+01:00","created_by":"gdiazlo","metadata":"{}"}]} 87 + {"id":"hcs-ddd","title":"Create HTTP/2 cross-language benchmark script","description":"Create run_h2_comparison.sh that starts all three servers (HCS, Rust, Go) and runs h2load benchmarks against each. Test /ping, /bytes/1024, /bytes/10240 endpoints. Output structured results for comparison.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T08:21:57.169092148+01:00","updated_at":"2025-12-30T08:48:51.028339202+01:00","closed_at":"2025-12-30T08:48:51.028339202+01:00","dependencies":[{"issue_id":"hcs-ddd","depends_on_id":"hcs-osg","type":"blocks","created_at":"2025-12-30T08:22:14.06532517+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-ddd","depends_on_id":"hcs-l9p","type":"blocks","created_at":"2025-12-30T08:22:16.71293984+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-ddd","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:25.823611037+01:00","created_by":"gdiazlo","metadata":"{}"}]} 88 + {"id":"hcs-dle","title":"Request/Response Helpers","description":"Implement Request and Response helper modules with body handling, status shortcuts, and codec integration.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:33.481216228+01:00","updated_at":"2025-12-29T15:40:53.163093449+01:00","closed_at":"2025-12-29T15:40:53.163093449+01:00","dependencies":[{"issue_id":"hcs-dle","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:17.959259297+01:00","created_by":"gdiazlo","metadata":"{}"}]} 89 + {"id":"hcs-dpu","title":"LAS: Project setup (dune, dependencies)","description":"Create bin/las/dune with libraries: hcs, caqti, caqti-driver-sqlite3, caqti-eio, yojson. Set up executable definition.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:22.138827845+01:00","updated_at":"2026-01-01T23:49:20.337195774+01:00","closed_at":"2026-01-01T23:49:20.337195774+01:00","dependencies":[{"issue_id":"hcs-dpu","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:18.213570142+01:00","created_by":"gdiazlo","metadata":"{}"}]} 90 + {"id":"hcs-dsf","title":"Set up project structure and dune build","description":"Set up the OCaml project structure with dune:\n\n```\nhcs/\n├── dune-project\n├── hcs-core/ # Pure, runtime-agnostic\n│ ├── dune\n│ ├── types.ml\n│ ├── error.ml\n│ ├── headers.ml\n│ ├── stream.ml # Synchronous stream operations\n│ ├── codec.ml\n│ └── hcs_core.ml # Public API re-exports\n├── hcs-eio/ # Eio runtime\n│ ├── dune\n│ ├── runtime.ml # RUNTIME implementation for Eio\n│ ├── client.ml\n│ ├── server.ml\n│ └── hcs_eio.ml\n└── hcs/ # Convenience package (re-exports hcs-eio)\n ├── dune\n └── hcs.ml\n```\n\nConfigure opam dependencies.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:26.717322855+01:00","updated_at":"2025-12-29T14:50:39.789609025+01:00","closed_at":"2025-12-29T14:50:39.789609025+01:00","labels":["infrastructure"],"dependencies":[{"issue_id":"hcs-dsf","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:43.02614445+01:00","created_by":"gdiazlo","metadata":"{}"}]} 91 + {"id":"hcs-dzr","title":"Create TechEmpower-style benchmark suite with hyper, fasthttp, and HCS servers","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-30T22:21:05.455078159+01:00","updated_at":"2025-12-30T22:33:15.399922114+01:00","closed_at":"2025-12-30T22:33:15.399922114+01:00"} 92 + {"id":"hcs-ez2","title":"Implement Content Negotiation","description":"Parse Accept headers and select response format.\n\n## Design\n\n### Core Types\n```ocaml\ntype media_type = {\n type_: string; (* e.g., \"application\" *)\n subtype: string; (* e.g., \"json\" *)\n quality: float; (* 0.0 - 1.0 *)\n params: (string * string) list;\n}\n\ntype format = Json | Html | Text | Xml | Custom of string\n```\n\n### Parser\n```ocaml\nval parse_accept : string -\u003e media_type list\n(* Returns sorted by quality, highest first *)\n```\n\n### Negotiation\n```ocaml\nval negotiate : accept:string -\u003e available:format list -\u003e format option\n(* Returns best match or None *)\n\nval negotiate_exn : accept:string -\u003e available:format list -\u003e format\n(* Returns best match or raises Not_acceptable *)\n```\n\n### Plug Integration\n```ocaml\nmodule Plug.Negotiate : sig\n val create : formats:format list -\u003e Plug.t\n (* Sets negotiated format in request, returns 406 if no match *)\nend\n\nval get_format : request -\u003e format option\n```\n\n### Response Helpers\n```ocaml\nval respond_format : format -\u003e body:string -\u003e response\n(* Sets correct Content-Type *)\n\nval respond_negotiate : request -\u003e \n json:(unit -\u003e string) -\u003e \n html:(unit -\u003e string) -\u003e \n response\n(* Lazy evaluation - only runs the selected format *)\n```\n\n### Performance\n- Single-pass parser, no regex\n- Pre-sorted available formats by preference\n- Lazy body generation (no allocation until format selected)","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:14.119965918+01:00","updated_at":"2026-01-01T21:01:33.869936139+01:00","closed_at":"2026-01-01T21:01:33.869936139+01:00","dependencies":[{"issue_id":"hcs-ez2","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:48:01.682801946+01:00","created_by":"gdiazlo","metadata":"{}"}]} 93 + {"id":"hcs-f2r","title":"Skip body reading for bodiless methods (GET/HEAD/DELETE)","description":"In h2_server.ml, skip Buffer.create, Promise.create, and body reading for GET/HEAD/DELETE methods. These have no body but currently allocate a buffer and promise.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:57:23.954431824+01:00","updated_at":"2025-12-30T09:01:38.714453571+01:00","closed_at":"2025-12-30T09:01:38.714453571+01:00","dependencies":[{"issue_id":"hcs-f2r","depends_on_id":"hcs-cq4","type":"parent-child","created_at":"2025-12-30T08:57:44.799141738+01:00","created_by":"gdiazlo","metadata":"{}"}]} 94 + {"id":"hcs-fgd","title":"Logging System","description":"Implement Log module with level, event types, built-in loggers (null, stderr, custom), and event formatting.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:26.517303879+01:00","updated_at":"2025-12-29T17:40:48.765669075+01:00","closed_at":"2025-12-29T17:40:48.765669075+01:00","dependencies":[{"issue_id":"hcs-fgd","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:08.827592455+01:00","created_by":"gdiazlo","metadata":"{}"}]} 95 + {"id":"hcs-fsc","title":"Implement Request helper module","description":"Implement request helpers in hcs-core/request.ml:\n\n```ocaml\nval path : request -\u003e string\nval query : string -\u003e request -\u003e string option\nval query_all : string -\u003e request -\u003e string list\nval header : string -\u003e request -\u003e string option\nval header_all : string -\u003e request -\u003e string list\nval content_type : request -\u003e string option\nval content_length : request -\u003e int64 option\nval is_keep_alive : request -\u003e bool\n\n(* Body consumption - sync versions *)\nval body_string : request -\u003e (string, error) result\nval body_to_cstruct : request -\u003e (Cstruct.t, error) result\n\n(* Form data parsing *)\nval form : request -\u003e ((string * string) list, error) result\n```\n\nPure OCaml + uri package.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:34:09.842512086+01:00","updated_at":"2025-12-29T15:40:29.136273489+01:00","closed_at":"2025-12-29T15:40:29.136273489+01:00","dependencies":[{"issue_id":"hcs-fsc","depends_on_id":"hcs-dle","type":"parent-child","created_at":"2025-12-29T14:34:47.838799048+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-fsc","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:34:54.851316989+01:00","created_by":"gdiazlo","metadata":"{}"}]} 96 + {"id":"hcs-g0z","title":"Move SSE status indicator to navigation bar","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T19:58:20.922098899+01:00","updated_at":"2026-01-02T20:18:11.064543523+01:00","closed_at":"2026-01-02T20:18:11.064543523+01:00"} 97 + {"id":"hcs-g2y","title":"Research HTTP compliance test suites","description":"Research and document available HTTP compliance testing tools and servers:\n\n**For Client Testing (test servers):**\n\n1. **httpbin** (https://httpbin.org / kennethreitz/httpbin)\n - Returns request info as JSON\n - Tests: methods, headers, redirects, auth, cookies, response codes\n - Can run locally via Docker\n\n2. **go-httpbin** (mccutchen/go-httpbin)\n - Go reimplementation, faster and more features\n - Better for local testing\n\n3. **h2spec** (summerwind/h2spec)\n - HTTP/2 conformance testing tool\n - Tests HPACK, streams, flow control, error handling\n - Essential for HTTP/2 compliance\n\n4. **curl test suite**\n - curl's own test servers have extensive edge cases\n\n**For Server Testing (test clients):**\n\n1. **h2load** (nghttp2)\n - HTTP/2 benchmarking and testing\n - Tests multiplexing, flow control\n\n2. **curl** with verbose options\n - Good for basic HTTP/1.1 compliance\n\n3. **nghttp** (nghttp2)\n - HTTP/2 client for testing server responses\n\n4. **Autobahn|Testsuite** (for WebSocket)\n - Comprehensive WebSocket protocol compliance\n - https://github.com/crossbario/autobahn-testsuite\n\n**RFC Compliance:**\n- RFC 7230-7235 (HTTP/1.1)\n- RFC 7540 (HTTP/2)\n- RFC 6455 (WebSocket)\n- RFC 7541 (HPACK)\n\nEvaluate which tools to integrate into CI.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:36:03.601972706+01:00","updated_at":"2025-12-29T17:31:46.947022974+01:00","closed_at":"2025-12-29T17:31:46.947022974+01:00","dependencies":[{"issue_id":"hcs-g2y","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:42.697870585+01:00","created_by":"gdiazlo","metadata":"{}"}]} 98 + {"id":"hcs-g40","title":"Update test/dune with mirage-crypto-rng dependency","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T22:16:47.415817521+01:00","updated_at":"2026-01-01T22:20:00.598342536+01:00","closed_at":"2026-01-01T22:20:00.598342536+01:00","dependencies":[{"issue_id":"hcs-g40","depends_on_id":"hcs-6t7","type":"blocks","created_at":"2026-01-01T22:17:01.18997103+01:00","created_by":"gdiazlo","metadata":"{}"}]} 99 + {"id":"hcs-gcwo","title":"Update README.md - add missing modules and plugs","status":"closed","priority":2,"issue_type":"chore","created_at":"2026-01-03T14:29:33.387794606+01:00","updated_at":"2026-01-03T14:32:09.316465513+01:00","closed_at":"2026-01-03T14:32:09.316465513+01:00"} 100 + {"id":"hcs-gii","title":"LAS: Database layer (db.ml)","description":"Caqti connection pool, schema initialization, queries for links/users/votes/comments. Use SQLite.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:32.219826186+01:00","updated_at":"2026-01-01T23:55:18.482315084+01:00","closed_at":"2026-01-01T23:55:18.482315084+01:00","dependencies":[{"issue_id":"hcs-gii","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:28.299766704+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-gii","depends_on_id":"hcs-y5a","type":"blocks","created_at":"2026-01-01T23:43:08.598843871+01:00","created_by":"gdiazlo","metadata":"{}"}]} 101 + {"id":"hcs-gmb","title":"Implement error type","description":"Implement comprehensive error type in error.ml:\n- Connection_failed, Connection_closed\n- Timeout variants (Connect, Read, Write, Total)\n- Cancelled\n- Invalid_url, Invalid_response\n- Too_many_redirects\n- Protocol_error, Tls_error, Codec_error\n- Body_too_large, IO_error\n\nInclude to_string for debugging. Pure OCaml.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:22.136715155+01:00","updated_at":"2025-12-29T14:50:40.75088559+01:00","closed_at":"2025-12-29T14:50:40.75088559+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-gmb","depends_on_id":"hcs-ugs","type":"parent-child","created_at":"2025-12-29T14:27:42.239579889+01:00","created_by":"gdiazlo","metadata":"{}"}]} 102 + {"id":"hcs-gr3","title":"Implement gzip and zstd compression/decompression functions","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:16.145810916+01:00","updated_at":"2026-01-01T18:47:23.516801771+01:00","closed_at":"2026-01-01T18:47:23.516801771+01:00","dependencies":[{"issue_id":"hcs-gr3","depends_on_id":"hcs-ro3","type":"blocks","created_at":"2026-01-01T18:44:41.614944047+01:00","created_by":"gdiazlo","metadata":"{}"}]} 103 + {"id":"hcs-h2a","title":"Benchmark runner script with memory profiling","description":"Create benchmark runner that tests all servers across all protocols, measures req/s, msg/s, memory/connection, and produces summary report.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-31T14:13:51.31059033+01:00","updated_at":"2025-12-31T14:47:32.444742919+01:00","closed_at":"2025-12-31T14:47:32.444742919+01:00","dependencies":[{"issue_id":"hcs-h2a","depends_on_id":"hcs-rzc","type":"blocks","created_at":"2025-12-31T14:14:05.717334469+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-9yc","type":"blocks","created_at":"2025-12-31T14:14:10.761462149+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-s94","type":"blocks","created_at":"2025-12-31T14:14:15.805316293+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-peu","type":"blocks","created_at":"2025-12-31T14:14:20.849391195+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-h2a","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:46.066127034+01:00","created_by":"gdiazlo","metadata":"{}"}]} 104 + {"id":"hcs-h2u","title":"Add circuit_breaker middleware to middleware_eio.ml","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:15:15.277426489+01:00","updated_at":"2026-01-01T18:16:24.778681979+01:00","closed_at":"2026-01-01T18:16:24.778681979+01:00"} 105 + {"id":"hcs-hamc","title":"docs: Rate Limiting recipe","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:54.179784921+01:00","updated_at":"2026-01-03T01:11:19.115496023+01:00","closed_at":"2026-01-03T01:11:19.115496023+01:00"} 106 + {"id":"hcs-hex4","title":"docs: JSON API recipe","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:45:09.305879766+01:00","updated_at":"2026-01-03T01:12:28.300845339+01:00","closed_at":"2026-01-03T01:12:28.300845339+01:00"} 107 + {"id":"hcs-hkf","title":"Add benchmark runner script with standard scenarios","description":"Create a benchmark runner script (bench/run_benchmarks.sh) that runs standard benchmark scenarios:\n1. Minimal GET (/ping) - pure overhead measurement\n2. Small payload (1KB) - typical API response\n3. Medium payload (10KB) - larger JSON responses \n4. Large payload (100KB) - file downloads\n5. POST with body - request body handling\n6. Varying concurrency (1, 10, 50, 100, 200 connections)\n7. HTTP/1.1 vs HTTP/2 comparison\n\nOutput results to bench/results/ with timestamps for tracking over time.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T18:04:02.294539956+01:00","updated_at":"2025-12-29T18:17:10.742622288+01:00","closed_at":"2025-12-29T18:17:10.742622288+01:00","dependencies":[{"issue_id":"hcs-hkf","depends_on_id":"hcs-jtz","type":"parent-child","created_at":"2025-12-29T18:04:24.660841757+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-hkf","depends_on_id":"hcs-4w8","type":"blocks","created_at":"2025-12-29T18:04:36.967445707+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-hkf","depends_on_id":"hcs-320","type":"blocks","created_at":"2025-12-29T18:04:38.425355179+01:00","created_by":"gdiazlo","metadata":"{}"}]} 108 + {"id":"hcs-i4f","title":"Setup bench/ directory structure with .gitignore","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:21.51511238+01:00","updated_at":"2025-12-30T22:23:03.029513364+01:00","closed_at":"2025-12-30T22:23:03.029513364+01:00"} 109 + {"id":"hcs-i8j","title":"Implement OCaml/HCS benchmark server (plaintext + json, HTTP/1+2, CPU scaling)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:36.638072425+01:00","updated_at":"2025-12-30T22:28:28.339092129+01:00","closed_at":"2025-12-30T22:28:28.339092129+01:00"} 110 + {"id":"hcs-j2z","title":"Implement unified Client module (Eio)","description":"Implement unified client API in hcs-eio/client.ml:\n\n```ocaml\ntype t\n\nval create :\n sw:Eio.Switch.t -\u003e\n net:Eio.Net.t -\u003e\n clock:Eio.Time.clock -\u003e\n ?config:config -\u003e\n unit -\u003e\n t\n\nval request : ?cancel:Cancel.t -\u003e t -\u003e request -\u003e (response, error) result\nval fetch : ?cancel:Cancel.t -\u003e t -\u003e request -\u003e (status * Headers.t * string, error) result\nval stream : ?cancel:Cancel.t -\u003e t -\u003e request -\u003e (status * Headers.t * Cstruct.t Stream.t, error) result\n\nval close_idle : t -\u003e unit\nval pool_stats : t -\u003e { active: int; idle: int; total: int }\n```\n\nFeatures:\n- Protocol selection (HTTP/1.1 vs HTTP/2) via ALPN or config\n- Connection pooling\n- Automatic redirect following\n- Compression handling\n- TLS with system certs by default","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:27.67982735+01:00","updated_at":"2025-12-29T17:00:20.730823454+01:00","closed_at":"2025-12-29T17:00:20.730823454+01:00","dependencies":[{"issue_id":"hcs-j2z","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:51.749045471+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-j2z","depends_on_id":"hcs-7n9","type":"blocks","created_at":"2025-12-29T14:31:54.365652586+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-j2z","depends_on_id":"hcs-d5s","type":"blocks","created_at":"2025-12-29T14:31:55.246269371+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-j2z","depends_on_id":"hcs-2ca","type":"blocks","created_at":"2025-12-29T14:31:55.835151512+01:00","created_by":"gdiazlo","metadata":"{}"}]} 111 + {"id":"hcs-j5q","title":"Move Go benchmark server to dedicated folder (bench/comparison/go_fasthttp/)","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-12-30T00:14:15.760072799+01:00","updated_at":"2025-12-30T00:17:18.571463212+01:00","closed_at":"2025-12-30T00:17:18.571463212+01:00"} 112 + {"id":"hcs-j7fj","title":"Update: Migrate las.ml to new App API","description":"Update bin/las/las.ml to use new API:\n- Change Hcs.Endpoint → Hcs.App\n- Create Server.config separately for network settings\n- Pass both App.t and Server.config to App.start\n- Update README tutorial if needed\n\nThis is the only consumer of Endpoint.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T20:59:41.77709642+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:11:13.189606663+01:00","closed_at":"2026-01-03T21:11:13.189606663+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-j7fj","depends_on_id":"hcs-pcri","type":"blocks","created_at":"2026-01-03T21:00:17.847507496+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-j7fj","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:24.580564444+01:00","created_by":"gdiazlo"}]} 113 + {"id":"hcs-j7j","title":"Implement Go/fasthttp benchmark server (plaintext + json, HTTP/1+2, CPU scaling)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:31.597229058+01:00","updated_at":"2025-12-30T22:28:28.338758567+01:00","closed_at":"2025-12-30T22:28:28.338758567+01:00"} 84 114 {"id":"hcs-jk8","title":"WebSocket Benchmark: Memory and Connection Scaling","description":"Compare HCS (OCaml) vs Go vs Rust WebSocket implementations. Metrics: memory per connection, max connections per CPU.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-30T09:59:44.349580383+01:00","updated_at":"2025-12-30T10:23:00.707208406+01:00","closed_at":"2025-12-30T10:23:00.707208406+01:00"} 85 - {"id":"hcs-jqx","title":"Cache :path header extraction in request_handler","description":"H2.Headers.get is O(n). For the :path pseudo-header which is always present and accessed for every request, consider direct access or caching.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T08:57:26.215703677+01:00","updated_at":"2025-12-30T09:01:43.754321197+01:00","closed_at":"2025-12-30T09:01:43.754321197+01:00","dependencies":[{"issue_id":"hcs-jqx","depends_on_id":"hcs-cq4","type":"parent-child","created_at":"2025-12-30T08:57:49.840282561+01:00","created_by":"gdiazlo"}]} 86 - {"id":"hcs-jsl","title":"Implement Path DSL","description":"Implement type-safe path DSL in hcs-core/path.ml:\n\n```ocaml\ntype 'a t\n\n(* Combinators *)\nval root : unit t (* / *)\nval const : string -\u003e unit t (* /literal *)\nval str : string t (* /:param - captures string *)\nval int : int t (* /:param - captures int *)\nval int32 : int32 t\nval int64 : int64 t\nval uuid : string t (* validates UUID format *)\nval rest : string list t (* /** - captures remaining *)\n\nval ( / ) : 'a t -\u003e 'b t -\u003e ('a * 'b) t\nval ( /: ) : unit t -\u003e 'a t -\u003e 'a t (* const / capture shorthand *)\n\nval trailing_slash : 'a t -\u003e 'a t\n\n(* For router compilation *)\ntype segment =\n | Literal of string\n | Param_string\n | Param_int\n | Param_int32\n | Param_int64 \n | Param_uuid\n | Wildcard\n\nval to_segments : 'a t -\u003e segment list\nval parse : 'a t -\u003e string list -\u003e ('a, string) result\n```\n\nPure OCaml, uses GADTs for type safety.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:32:24.842727479+01:00","updated_at":"2025-12-29T14:56:33.544162475+01:00","closed_at":"2025-12-29T14:56:33.544162475+01:00","dependencies":[{"issue_id":"hcs-jsl","depends_on_id":"hcs-2ie","type":"parent-child","created_at":"2025-12-29T14:32:55.556666992+01:00","created_by":"gdiazlo"}]} 115 + {"id":"hcs-jqx","title":"Cache :path header extraction in request_handler","description":"H2.Headers.get is O(n). For the :path pseudo-header which is always present and accessed for every request, consider direct access or caching.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T08:57:26.215703677+01:00","updated_at":"2025-12-30T09:01:43.754321197+01:00","closed_at":"2025-12-30T09:01:43.754321197+01:00","dependencies":[{"issue_id":"hcs-jqx","depends_on_id":"hcs-cq4","type":"parent-child","created_at":"2025-12-30T08:57:49.840282561+01:00","created_by":"gdiazlo","metadata":"{}"}]} 116 + {"id":"hcs-jsl","title":"Implement Path DSL","description":"Implement type-safe path DSL in hcs-core/path.ml:\n\n```ocaml\ntype 'a t\n\n(* Combinators *)\nval root : unit t (* / *)\nval const : string -\u003e unit t (* /literal *)\nval str : string t (* /:param - captures string *)\nval int : int t (* /:param - captures int *)\nval int32 : int32 t\nval int64 : int64 t\nval uuid : string t (* validates UUID format *)\nval rest : string list t (* /** - captures remaining *)\n\nval ( / ) : 'a t -\u003e 'b t -\u003e ('a * 'b) t\nval ( /: ) : unit t -\u003e 'a t -\u003e 'a t (* const / capture shorthand *)\n\nval trailing_slash : 'a t -\u003e 'a t\n\n(* For router compilation *)\ntype segment =\n | Literal of string\n | Param_string\n | Param_int\n | Param_int32\n | Param_int64 \n | Param_uuid\n | Wildcard\n\nval to_segments : 'a t -\u003e segment list\nval parse : 'a t -\u003e string list -\u003e ('a, string) result\n```\n\nPure OCaml, uses GADTs for type safety.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:32:24.842727479+01:00","updated_at":"2025-12-29T14:56:33.544162475+01:00","closed_at":"2025-12-29T14:56:33.544162475+01:00","dependencies":[{"issue_id":"hcs-jsl","depends_on_id":"hcs-2ie","type":"parent-child","created_at":"2025-12-29T14:32:55.556666992+01:00","created_by":"gdiazlo","metadata":"{}"}]} 87 117 {"id":"hcs-jtz","title":"Benchmark Suite for HCS HTTP Library","description":"Create a comprehensive benchmark suite to measure HCS HTTP library performance. Focus on requests/second for both HTTP/1.1 and HTTP/2, comparing client and server performance under various conditions.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T18:03:37.371206713+01:00","updated_at":"2025-12-29T18:18:17.12058364+01:00","closed_at":"2025-12-29T18:18:17.12058364+01:00"} 88 - {"id":"hcs-k8f","title":"Implement multi-domain server run functions","description":"Create run_parallel and run_parallel_opt functions that spawn N domains, each with their own accept loop using SO_REUSEPORT.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:54.711085855+01:00","updated_at":"2025-12-30T09:10:52.550223218+01:00","closed_at":"2025-12-30T09:10:52.550223218+01:00","dependencies":[{"issue_id":"hcs-k8f","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:19.149511092+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-k8f","depends_on_id":"hcs-cxj","type":"blocks","created_at":"2025-12-30T09:06:34.264044099+01:00","created_by":"gdiazlo"}]} 89 - {"id":"hcs-kfm","title":"Set up property-based testing for parsers","description":"Use property-based testing (QCheck or Crowbar) for parsers and router:\n\n1. **HTTP/1.1 parser properties:**\n - parse(serialize(request)) = request (roundtrip)\n - parse partial input = Incomplete\n - parse garbage = Error (no crashes)\n - parse valid + garbage = Complete with correct consumed bytes\n\n2. **Router properties:**\n - All registered routes are matchable\n - More specific routes match before less specific\n - No path matches multiple routes (deterministic)\n - Captured params have correct types\n\n3. **Headers properties:**\n - Case-insensitive lookup\n - add then find = Some value\n - remove then find = None\n - of_list(to_list(h)) preserves all values\n\n4. **WebSocket frame properties:**\n - parse(serialize(frame)) = frame\n - Masked frames unmask correctly\n - Fragmented messages reassemble correctly\n\nAdd to dune test configuration with reasonable iteration counts.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:30.160273757+01:00","updated_at":"2025-12-29T17:52:17.694190669+01:00","closed_at":"2025-12-29T17:52:17.694190669+01:00","dependencies":[{"issue_id":"hcs-kfm","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:52.71433591+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-kfm","depends_on_id":"hcs-8zr","type":"blocks","created_at":"2025-12-29T14:37:00.796778902+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-kfm","depends_on_id":"hcs-sny","type":"blocks","created_at":"2025-12-29T14:37:01.737277561+01:00","created_by":"gdiazlo"}]} 90 - {"id":"hcs-kg1","title":"Implement connection pool","description":"Implement connection pooling with runtime abstraction:\n\nhcs-core/pool.ml (data structures):\n```ocaml\ntype key = { host: string; port: int; is_tls: bool }\ntype 'conn entry = { conn: 'conn; last_used: float; created: float }\ntype 'conn t\n\nval create : max_per_host:int -\u003e max_total:int -\u003e 'conn t\nval get : 'conn t -\u003e key -\u003e 'conn entry option\nval put : 'conn t -\u003e key -\u003e 'conn -\u003e now:float -\u003e unit\nval remove : 'conn t -\u003e key -\u003e 'conn -\u003e unit\nval close_idle : 'conn t -\u003e older_than:float -\u003e 'conn list\nval stats : 'conn t -\u003e { active: int; idle: int; total: int }\n```\n\nhcs-eio/pool.ml (Eio-specific):\n```ocaml\nmodule Eio_pool : sig\n type t\n val create : config:Client.config -\u003e t\n val acquire : t -\u003e key -\u003e (Eio.Flow.two_way, error) result\n val release : t -\u003e key -\u003e Eio.Flow.two_way -\u003e unit\n val with_connection : t -\u003e key -\u003e (Eio.Flow.two_way -\u003e 'a) -\u003e ('a, error) result\nend\n```\n\nUse LRU eviction, health checks on reuse.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:11.052080452+01:00","updated_at":"2025-12-29T15:18:04.471112737+01:00","closed_at":"2025-12-29T15:18:04.471112737+01:00","dependencies":[{"issue_id":"hcs-kg1","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:44.252516545+01:00","created_by":"gdiazlo"}]} 91 - {"id":"hcs-l23","title":"HTTP Client DSL","description":"Implement the Http module with request builder DSL for fluent API including headers, query params, body, and codec integration.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:29.533679497+01:00","updated_at":"2025-12-29T17:40:50.224704889+01:00","closed_at":"2025-12-29T17:40:50.224704889+01:00","dependencies":[{"issue_id":"hcs-l23","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:13.135112824+01:00","created_by":"gdiazlo"}]} 92 - {"id":"hcs-l3v","title":"Implement PubSub and Channels","description":"Real-time pub/sub messaging and structured WebSocket channels.\n\n## Design\n\n### PubSub Core\n```ocaml\nmodule PubSub : sig\n type t\n type topic = string\n type message = string (* Keep simple, user serializes *)\n \n val create : unit -\u003e t\n val subscribe : t -\u003e topic -\u003e (message -\u003e unit) -\u003e subscription\n val unsubscribe : subscription -\u003e unit\n val broadcast : t -\u003e topic -\u003e message -\u003e unit\n val direct : t -\u003e subscriber_id:string -\u003e message -\u003e unit\nend\n```\n\n### Channel (WebSocket abstraction)\n```ocaml\nmodule Channel : sig\n type t\n type event = { topic: string; event: string; payload: string }\n \n val join : t -\u003e topic:string -\u003e params:string -\u003e (unit, string) result\n val leave : t -\u003e topic:string -\u003e unit\n val push : t -\u003e topic:string -\u003e event:string -\u003e payload:string -\u003e unit\n val on : t -\u003e event:string -\u003e (event -\u003e unit) -\u003e unit\nend\n```\n\n### Handler Pattern\n```ocaml\nmodule type Channel_handler = sig\n val join : params:string -\u003e socket:Channel.t -\u003e (unit, string) result\n val handle_in : event:string -\u003e payload:string -\u003e socket:Channel.t -\u003e unit\n val handle_info : message:PubSub.message -\u003e socket:Channel.t -\u003e unit\n val leave : socket:Channel.t -\u003e unit\nend\n```\n\n### Wire Protocol (simple JSON)\n```json\n{\"t\": \"room:123\", \"e\": \"msg\", \"p\": \"...\", \"r\": 1}\n topic event payload ref(for replies)\n```\n\n### Implementation\n1. **PubSub backend** - In-process Hashtbl of topic -\u003e subscriber list\n2. **Channel socket** - Wraps WebSocket with topic subscriptions\n3. **Multiplexing** - Single WebSocket, multiple topic subscriptions\n\n### Performance\n- Topic matching: simple string equality (no wildcards for v1)\n- Message fanout: iterate subscriber list directly\n- No copying: same message string to all subscribers\n- Connection cleanup: unsubscribe all on disconnect","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:35.204055877+01:00","updated_at":"2026-01-01T21:34:06.786928112+01:00","closed_at":"2026-01-01T21:34:06.786928112+01:00","dependencies":[{"issue_id":"hcs-l3v","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:48:11.757915308+01:00","created_by":"gdiazlo"}]} 93 - {"id":"hcs-l9p","title":"Create Go HTTP/2 benchmark server (net/http)","description":"Implement a Go HTTP/2 server using net/http with h2c support. Match endpoints: /ping, /bytes/:n, /json. Use golang.org/x/net/http2/h2c for cleartext HTTP/2. Pre-allocate response buffers.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:21:53.967258404+01:00","updated_at":"2025-12-30T08:48:32.173036222+01:00","closed_at":"2025-12-30T08:48:32.173036222+01:00","dependencies":[{"issue_id":"hcs-l9p","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:23.072848194+01:00","created_by":"gdiazlo"}]} 118 + {"id":"hcs-jy8c","title":"docs: Static Files recipe","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:45:04.261903873+01:00","updated_at":"2026-01-03T01:20:01.38269864+01:00","closed_at":"2026-01-03T01:20:01.38269864+01:00"} 119 + {"id":"hcs-k8f","title":"Implement multi-domain server run functions","description":"Create run_parallel and run_parallel_opt functions that spawn N domains, each with their own accept loop using SO_REUSEPORT.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:54.711085855+01:00","updated_at":"2025-12-30T09:10:52.550223218+01:00","closed_at":"2025-12-30T09:10:52.550223218+01:00","dependencies":[{"issue_id":"hcs-k8f","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:19.149511092+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-k8f","depends_on_id":"hcs-cxj","type":"blocks","created_at":"2025-12-30T09:06:34.264044099+01:00","created_by":"gdiazlo","metadata":"{}"}]} 120 + {"id":"hcs-kco1","title":"docs: HTTP/2 Client guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:57.012043427+01:00","updated_at":"2026-01-03T01:20:01.382074867+01:00","closed_at":"2026-01-03T01:20:01.382074867+01:00"} 121 + {"id":"hcs-kfm","title":"Set up property-based testing for parsers","description":"Use property-based testing (QCheck or Crowbar) for parsers and router:\n\n1. **HTTP/1.1 parser properties:**\n - parse(serialize(request)) = request (roundtrip)\n - parse partial input = Incomplete\n - parse garbage = Error (no crashes)\n - parse valid + garbage = Complete with correct consumed bytes\n\n2. **Router properties:**\n - All registered routes are matchable\n - More specific routes match before less specific\n - No path matches multiple routes (deterministic)\n - Captured params have correct types\n\n3. **Headers properties:**\n - Case-insensitive lookup\n - add then find = Some value\n - remove then find = None\n - of_list(to_list(h)) preserves all values\n\n4. **WebSocket frame properties:**\n - parse(serialize(frame)) = frame\n - Masked frames unmask correctly\n - Fragmented messages reassemble correctly\n\nAdd to dune test configuration with reasonable iteration counts.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:36:30.160273757+01:00","updated_at":"2025-12-29T17:52:17.694190669+01:00","closed_at":"2025-12-29T17:52:17.694190669+01:00","dependencies":[{"issue_id":"hcs-kfm","depends_on_id":"hcs-0zq","type":"parent-child","created_at":"2025-12-29T14:36:52.71433591+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-kfm","depends_on_id":"hcs-8zr","type":"blocks","created_at":"2025-12-29T14:37:00.796778902+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-kfm","depends_on_id":"hcs-sny","type":"blocks","created_at":"2025-12-29T14:37:01.737277561+01:00","created_by":"gdiazlo","metadata":"{}"}]} 122 + {"id":"hcs-kg1","title":"Implement connection pool","description":"Implement connection pooling with runtime abstraction:\n\nhcs-core/pool.ml (data structures):\n```ocaml\ntype key = { host: string; port: int; is_tls: bool }\ntype 'conn entry = { conn: 'conn; last_used: float; created: float }\ntype 'conn t\n\nval create : max_per_host:int -\u003e max_total:int -\u003e 'conn t\nval get : 'conn t -\u003e key -\u003e 'conn entry option\nval put : 'conn t -\u003e key -\u003e 'conn -\u003e now:float -\u003e unit\nval remove : 'conn t -\u003e key -\u003e 'conn -\u003e unit\nval close_idle : 'conn t -\u003e older_than:float -\u003e 'conn list\nval stats : 'conn t -\u003e { active: int; idle: int; total: int }\n```\n\nhcs-eio/pool.ml (Eio-specific):\n```ocaml\nmodule Eio_pool : sig\n type t\n val create : config:Client.config -\u003e t\n val acquire : t -\u003e key -\u003e (Eio.Flow.two_way, error) result\n val release : t -\u003e key -\u003e Eio.Flow.two_way -\u003e unit\n val with_connection : t -\u003e key -\u003e (Eio.Flow.two_way -\u003e 'a) -\u003e ('a, error) result\nend\n```\n\nUse LRU eviction, health checks on reuse.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:31:11.052080452+01:00","updated_at":"2025-12-29T15:18:04.471112737+01:00","closed_at":"2025-12-29T15:18:04.471112737+01:00","dependencies":[{"issue_id":"hcs-kg1","depends_on_id":"hcs-qnb","type":"parent-child","created_at":"2025-12-29T14:31:44.252516545+01:00","created_by":"gdiazlo","metadata":"{}"}]} 123 + {"id":"hcs-ku12","title":"Fix Cstruct.to_bigarray slice copy in streaming writes","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T11:32:30.782288109+01:00","updated_at":"2026-01-03T11:35:35.970107645+01:00","closed_at":"2026-01-03T11:35:35.970107645+01:00"} 124 + {"id":"hcs-l23","title":"HTTP Client DSL","description":"Implement the Http module with request builder DSL for fluent API including headers, query params, body, and codec integration.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:29.533679497+01:00","updated_at":"2025-12-29T17:40:50.224704889+01:00","closed_at":"2025-12-29T17:40:50.224704889+01:00","dependencies":[{"issue_id":"hcs-l23","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:13.135112824+01:00","created_by":"gdiazlo","metadata":"{}"}]} 125 + {"id":"hcs-l3v","title":"Implement PubSub and Channels","description":"Real-time pub/sub messaging and structured WebSocket channels.\n\n## Design\n\n### PubSub Core\n```ocaml\nmodule PubSub : sig\n type t\n type topic = string\n type message = string (* Keep simple, user serializes *)\n \n val create : unit -\u003e t\n val subscribe : t -\u003e topic -\u003e (message -\u003e unit) -\u003e subscription\n val unsubscribe : subscription -\u003e unit\n val broadcast : t -\u003e topic -\u003e message -\u003e unit\n val direct : t -\u003e subscriber_id:string -\u003e message -\u003e unit\nend\n```\n\n### Channel (WebSocket abstraction)\n```ocaml\nmodule Channel : sig\n type t\n type event = { topic: string; event: string; payload: string }\n \n val join : t -\u003e topic:string -\u003e params:string -\u003e (unit, string) result\n val leave : t -\u003e topic:string -\u003e unit\n val push : t -\u003e topic:string -\u003e event:string -\u003e payload:string -\u003e unit\n val on : t -\u003e event:string -\u003e (event -\u003e unit) -\u003e unit\nend\n```\n\n### Handler Pattern\n```ocaml\nmodule type Channel_handler = sig\n val join : params:string -\u003e socket:Channel.t -\u003e (unit, string) result\n val handle_in : event:string -\u003e payload:string -\u003e socket:Channel.t -\u003e unit\n val handle_info : message:PubSub.message -\u003e socket:Channel.t -\u003e unit\n val leave : socket:Channel.t -\u003e unit\nend\n```\n\n### Wire Protocol (simple JSON)\n```json\n{\"t\": \"room:123\", \"e\": \"msg\", \"p\": \"...\", \"r\": 1}\n topic event payload ref(for replies)\n```\n\n### Implementation\n1. **PubSub backend** - In-process Hashtbl of topic -\u003e subscriber list\n2. **Channel socket** - Wraps WebSocket with topic subscriptions\n3. **Multiplexing** - Single WebSocket, multiple topic subscriptions\n\n### Performance\n- Topic matching: simple string equality (no wildcards for v1)\n- Message fanout: iterate subscriber list directly\n- No copying: same message string to all subscribers\n- Connection cleanup: unsubscribe all on disconnect","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:35.204055877+01:00","updated_at":"2026-01-01T21:34:06.786928112+01:00","closed_at":"2026-01-01T21:34:06.786928112+01:00","dependencies":[{"issue_id":"hcs-l3v","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:48:11.757915308+01:00","created_by":"gdiazlo","metadata":"{}"}]} 126 + {"id":"hcs-l99","title":"LAS SSE heartbeat keepalive","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T14:41:16.893562107+01:00","updated_at":"2026-01-02T14:41:52.627600409+01:00","closed_at":"2026-01-02T14:41:52.627600409+01:00"} 127 + {"id":"hcs-l9p","title":"Create Go HTTP/2 benchmark server (net/http)","description":"Implement a Go HTTP/2 server using net/http with h2c support. Match endpoints: /ping, /bytes/:n, /json. Use golang.org/x/net/http2/h2c for cleartext HTTP/2. Pre-allocate response buffers.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:21:53.967258404+01:00","updated_at":"2025-12-30T08:48:32.173036222+01:00","closed_at":"2025-12-30T08:48:32.173036222+01:00","dependencies":[{"issue_id":"hcs-l9p","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:23.072848194+01:00","created_by":"gdiazlo","metadata":"{}"}]} 94 128 {"id":"hcs-le4","title":"Add streaming compression support for Body_stream responses","description":"Current compress middleware buffers entire response before compressing, making it ineffective for Body_stream responses. Need to:\n\n1. Add gzip_compress_stream that wraps Body_stream with streaming gzip compression using Zlib.flate with Sync_flush\n2. Add decompress_request middleware for incoming Content-Encoding: gzip/zstd bodies\n3. Zstd streaming NOT supported by OCaml bindings - will buffer and compress\n\nTechnical notes:\n- Body_stream has signature: next : unit -\u003e Cstruct.t option\n- Zlib supports streaming via flate with No_flush/Sync_flush/Finish flush modes\n- window_bits=31 for gzip format","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T19:01:22.570936835+01:00","updated_at":"2026-01-01T19:08:23.118608559+01:00","closed_at":"2026-01-01T19:08:23.118608559+01:00"} 95 - {"id":"hcs-lhr","title":"WebSocket Support","description":"Implement Ws module with frame types, connection management, send/recv operations, server upgrade handler, and client connect.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:36.29066838+01:00","updated_at":"2025-12-29T16:01:05.272490486+01:00","closed_at":"2025-12-29T16:01:05.272490486+01:00","dependencies":[{"issue_id":"hcs-lhr","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:20.036599039+01:00","created_by":"gdiazlo"}]} 96 - {"id":"hcs-llr","title":"Implement Rust/hyper benchmark server (plaintext + json, HTTP/1+2, CPU scaling)","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:26.556966252+01:00","updated_at":"2025-12-30T22:28:28.337697653+01:00","closed_at":"2025-12-30T22:28:28.337697653+01:00"} 97 - {"id":"hcs-lpr","title":"Implement request and response record types","description":"Implement request and response records in types.ml:\n\n```ocaml\ntype request = {\n meth : method_;\n uri : Uri.t;\n version : version;\n headers : Headers.t;\n body : body;\n}\n\ntype response = {\n status : status;\n version : version;\n headers : Headers.t;\n body : body;\n}\n```\n\nInclude smart constructors and accessors. Pure OCaml + uri package.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:19.295375903+01:00","updated_at":"2025-12-29T14:50:46.801981182+01:00","closed_at":"2025-12-29T14:50:46.801981182+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-lpr","depends_on_id":"hcs-ugs","type":"blocks","created_at":"2025-12-29T14:27:19.300960037+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-6yl","type":"blocks","created_at":"2025-12-29T14:27:43.920564401+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-cmg","type":"blocks","created_at":"2025-12-29T14:27:44.815114113+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-cks","type":"blocks","created_at":"2025-12-29T14:27:45.656483969+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-chm","type":"blocks","created_at":"2025-12-29T14:27:46.481924426+01:00","created_by":"gdiazlo"}]} 98 - {"id":"hcs-lqi","title":"Implement HTTP/1.1 server (Eio)","description":"Implement HTTP/1.1 server for Eio in hcs-eio/h1_server.ml:\n\n```ocaml\nval handle_connection :\n flow:Eio.Flow.two_way -\u003e\n clock:Eio.Time.clock -\u003e\n config:Server.config -\u003e\n handler:(request -\u003e (response, error) result) -\u003e\n unit\n```\n\nFeatures:\n- Parse requests using h1 parser\n- Handle keep-alive connections\n- Support chunked and fixed-length bodies\n- Respect timeouts\n- Handle pipelining (optional)\n- Integrate with logging","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:22.560229088+01:00","updated_at":"2025-12-29T15:03:24.765221644+01:00","closed_at":"2025-12-29T15:03:24.765221644+01:00","dependencies":[{"issue_id":"hcs-lqi","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:42.102983428+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-lqi","depends_on_id":"hcs-56z","type":"blocks","created_at":"2025-12-29T14:33:44.325287786+01:00","created_by":"gdiazlo"}]} 99 - {"id":"hcs-m4r","title":"Codec System","description":"Implement the functor-based CODEC signature and With_codec functor for type-safe serialization/deserialization. Use Cstruct.t (buffers) instead of strings to properly support binary formats like MessagePack, Protobuf, and CBOR.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:22.203715886+01:00","updated_at":"2025-12-29T17:40:46.982752973+01:00","closed_at":"2025-12-29T17:40:46.982752973+01:00","dependencies":[{"issue_id":"hcs-m4r","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:00.496780385+01:00","created_by":"gdiazlo"}]} 100 - {"id":"hcs-mip","title":"Implement Http request builder DSL","description":"Implement high-level client DSL in hcs-core/http.ml:\n\n```ocaml\ntype builder\n\nval get : string -\u003e (builder, error) result\nval post : string -\u003e (builder, error) result\nval put : string -\u003e (builder, error) result\nval delete : string -\u003e (builder, error) result\n(* ... other methods ... *)\n\nval of_uri : method_ -\u003e Uri.t -\u003e builder\n\n(* Headers *)\nval header : string -\u003e string -\u003e builder -\u003e builder\nval headers : (string * string) list -\u003e builder -\u003e builder\nval content_type : string -\u003e builder -\u003e builder\nval accept : string -\u003e builder -\u003e builder\nval bearer : string -\u003e builder -\u003e builder\nval basic_auth : user:string -\u003e pass:string -\u003e builder -\u003e builder\nval user_agent : string -\u003e builder -\u003e builder\n\n(* Query parameters *)\nval query : string -\u003e string -\u003e builder -\u003e builder\nval queries : (string * string) list -\u003e builder -\u003e builder\n\n(* Body *)\nval body : body -\u003e builder -\u003e builder\nval body_string : ?content_type:string -\u003e string -\u003e builder -\u003e builder\nval form : (string * string) list -\u003e builder -\u003e builder\n\n(* Build final request *)\nval build : builder -\u003e request\n```\n\nPure OCaml, no IO.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:22.698743046+01:00","updated_at":"2025-12-29T17:10:04.149286655+01:00","closed_at":"2025-12-29T17:10:04.149286655+01:00","dependencies":[{"issue_id":"hcs-mip","depends_on_id":"hcs-l23","type":"parent-child","created_at":"2025-12-29T14:34:49.5612417+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-mip","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:34:56.47577088+01:00","created_by":"gdiazlo"}]} 101 - {"id":"hcs-mli","title":"Run multi-CPU benchmarks (4, 8, 16 CPUs)","description":"Run benchmarks with 4, 8, and 16 domains for HCS, compare with Rust and Go multi-threaded.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:59.450548339+01:00","updated_at":"2025-12-30T09:16:49.37792589+01:00","closed_at":"2025-12-30T09:16:49.37792589+01:00","dependencies":[{"issue_id":"hcs-mli","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:29.226366436+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-mli","depends_on_id":"hcs-zln","type":"blocks","created_at":"2025-12-30T09:06:44.348550935+01:00","created_by":"gdiazlo"}]} 102 - {"id":"hcs-nad","title":"Implement WebSocket connection (Eio)","description":"Implement WebSocket for Eio in hcs-eio/websocket.ml:\n\n```ocaml\ntype conn\n\nval is_open : conn -\u003e bool\n\n(* Receive *)\nval recv : conn -\u003e (frame option, error) result\nval recv_timeout : Eio.Time.clock -\u003e float -\u003e conn -\u003e (frame option, error) result\n\n(* Send *)\nval send : conn -\u003e frame -\u003e (unit, error) result\nval close : ?code:int -\u003e ?reason:string -\u003e conn -\u003e (unit, error) result\n\n(* Stream interface *)\nval recv_stream : conn -\u003e frame Stream.t\nval send_stream : conn -\u003e frame Stream.t -\u003e (unit, error) result\n\n(* Server: upgrade handler *)\nval upgrade :\n ?protocols:string list -\u003e\n ?on_close:(int option -\u003e string option -\u003e unit) -\u003e\n (conn -\u003e (unit, error) result) -\u003e\n unit handler\n\n(* Client: connect *)\nval connect :\n sw:Eio.Switch.t -\u003e\n net:Eio.Net.t -\u003e\n clock:Eio.Time.clock -\u003e\n ?tls:Tls_config.client -\u003e\n ?headers:Headers.t -\u003e\n ?protocols:string list -\u003e\n string -\u003e\n (conn, error) result\n```","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:33.686889707+01:00","updated_at":"2025-12-29T16:00:45.086724651+01:00","closed_at":"2025-12-29T16:00:45.086724651+01:00","dependencies":[{"issue_id":"hcs-nad","depends_on_id":"hcs-lhr","type":"parent-child","created_at":"2025-12-29T14:34:52.929848888+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-nad","depends_on_id":"hcs-0ro","type":"blocks","created_at":"2025-12-29T14:34:58.053806421+01:00","created_by":"gdiazlo"}]} 103 - {"id":"hcs-njk","title":"Run HTTP/2 comparison benchmarks and analyze results","description":"Execute the HTTP/2 benchmarks across all three implementations. Collect req/s, latency (p50/p99), memory usage. Document results in BENCHMARKS.md with analysis of performance characteristics.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T08:21:59.417171367+01:00","updated_at":"2025-12-30T08:48:51.035410704+01:00","closed_at":"2025-12-30T08:48:51.035410704+01:00","dependencies":[{"issue_id":"hcs-njk","depends_on_id":"hcs-ddd","type":"blocks","created_at":"2025-12-30T08:22:17.716250574+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-njk","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:28.307104582+01:00","created_by":"gdiazlo"}]} 104 - {"id":"hcs-nwb","title":"LAS: Route definitions (routes.ml)","description":"Router.compile with all routes. Apply content negotiation to appropriate endpoints. Rate limit submissions.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:47.344395357+01:00","updated_at":"2026-01-02T10:27:11.186653396+01:00","closed_at":"2026-01-02T10:27:11.186653396+01:00","dependencies":[{"issue_id":"hcs-nwb","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:43.416555822+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-nwb","depends_on_id":"hcs-yg6","type":"blocks","created_at":"2026-01-01T23:43:43.888397319+01:00","created_by":"gdiazlo"}]} 105 - {"id":"hcs-oo5","title":"Benchmark suite: single-CPU comparison of HCS, hyper, fasthttp","description":"","notes":"## Benchmark Results (Dec 31, 2025)\n\n### HCS vs Eio Native (c=1000, 100k requests)\n\n| Domains | HCS run_parallel | Eio run_server | Winner |\n|---------|------------------|----------------|--------|\n| 1 | 142k | 136k | HCS +4% |\n| 2 | 196k | 200k | Eio +2% |\n| 4 | 264k | 259k | HCS +2% |\n| 8 | 259k | 267k | Eio +3% |\n\n**Key Finding**: Both approaches perform similarly. The 2-domain regression previously observed was a measurement artifact.\n\n### HCS vs Fasthttp (c=1000, 100k requests)\n\n| Domains | HCS | Fasthttp | Winner |\n|---------|-----|----------|--------|\n| 1 | 137k | 181k | Fasthttp +32% |\n| 4 | 242k | 186k | **HCS +30%** |\n| 8 | 228k | 204k | **HCS +12%** |\n\n**Key Finding**: HCS scales BETTER than Fasthttp and beats it at 4+ domains!\n\n### Conclusions\n\n1. The nested `Eio_main.run` is NOT a problem - Eio's Domain_manager.run does the same thing internally\n2. SO_REUSEPORT (HCS) vs shared socket (Eio native) perform similarly - no clear winner\n3. HCS multi-core scaling is actually quite good - beats Fasthttp at higher core counts\n4. Earlier \"2-domain regression\" was likely a measurement artifact (port reuse, warmup, etc.)\n\n### Remaining Optimization Opportunities\n\n1. Single-core performance still lags Fasthttp by ~32% - room for improvement in request parsing/response writing\n2. 8-domain shows slight regression from 4-domain for HCS - could investigate GC tuning\n3. Hyper benchmark failed to run - need to fix for comparison","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-30T22:41:13.187711389+01:00","updated_at":"2025-12-31T09:33:51.051037492+01:00","closed_at":"2025-12-31T09:33:51.051037492+01:00"} 106 - {"id":"hcs-oqc","title":"Implement signed/encrypted Tokens","description":"Signed and encrypted tokens for auth, password reset, email verification.\n\n## Design\n\n### Core API\n```ocaml\nmodule Token : sig\n type t\n \n val sign : secret:string -\u003e data:string -\u003e max_age:float -\u003e string\n val verify : secret:string -\u003e token:string -\u003e (string, error) result\n \n val encrypt : secret:string -\u003e data:string -\u003e max_age:float -\u003e string \n val decrypt : secret:string -\u003e token:string -\u003e (string, error) result\nend\n```\n\n### Token Format\n```\nsigned: base64(data) . timestamp . base64(hmac)\nencrypted: base64(nonce + ciphertext + tag) . timestamp . base64(hmac)\n```\n\n### Implementation\n- Use existing `digestif` for HMAC-SHA256\n- Use existing `mirage-crypto` for AES-GCM encryption\n- Timestamp encoded as varint for compactness\n- Single allocation for final token string\n\n### Use Cases\n```ocaml\n(* Auth token *)\nlet token = Token.sign ~secret ~data:user_id ~max_age:86400.0\n\n(* Password reset - encrypted so user can't see payload *)\nlet token = Token.encrypt ~secret ~data:user_id ~max_age:3600.0\n\n(* Verify *)\nmatch Token.verify ~secret token with\n| Ok user_id -\u003e ...\n| Error Token.Expired -\u003e ...\n| Error Token.Invalid -\u003e ...\n```\n\n### Performance\n- No JSON parsing, raw bytes\n- Constant-time comparison for signatures\n- Reuse crypto contexts where possible","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:03.67375632+01:00","updated_at":"2026-01-01T21:07:48.604332258+01:00","closed_at":"2026-01-01T21:07:48.604332258+01:00","dependencies":[{"issue_id":"hcs-oqc","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:47:56.644986614+01:00","created_by":"gdiazlo"}]} 107 - {"id":"hcs-osg","title":"Create Rust HTTP/2 benchmark server (hyper)","description":"Implement a Rust HTTP/2 server using hyper with h2c (cleartext HTTP/2) support. Match endpoints: /ping, /bytes/:n, /json. Use tokio runtime, pre-allocate response buffers for zero-copy.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:21:52.194368992+01:00","updated_at":"2025-12-30T08:48:32.166538953+01:00","closed_at":"2025-12-30T08:48:32.166538953+01:00","dependencies":[{"issue_id":"hcs-osg","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:20.416305094+01:00","created_by":"gdiazlo"}]} 108 - {"id":"hcs-peu","title":"HCS benchmark client: HTTP/1.1 + HTTP/2 + WebSocket support","description":"Create comprehensive benchmark client supporting all protocols with connection reuse, multiplexing, and WebSocket message throughput.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:46.273123556+01:00","updated_at":"2025-12-31T14:37:50.862757453+01:00","closed_at":"2025-12-31T14:37:50.862757453+01:00","dependencies":[{"issue_id":"hcs-peu","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:41.0222415+01:00","created_by":"gdiazlo"}]} 109 - {"id":"hcs-pnc","title":"Control Flow and Cancellation","description":"Implement Cancel module for cooperative cancellation and Control module for timeout, retry, deadline, and circuit breaker patterns.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:23.840150584+01:00","updated_at":"2025-12-29T15:41:49.225247023+01:00","closed_at":"2025-12-29T15:41:49.225247023+01:00","dependencies":[{"issue_id":"hcs-pnc","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:03.266144948+01:00","created_by":"gdiazlo"}]} 110 - {"id":"hcs-pod","title":"LAS: HTML views (views.ml)","description":"Layout template, link list, link detail, login/register forms, submit form. Include CSRF tokens in forms.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T23:41:42.302380219+01:00","updated_at":"2026-01-01T23:55:18.489268725+01:00","closed_at":"2026-01-01T23:55:18.489268725+01:00","dependencies":[{"issue_id":"hcs-pod","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:38.379707386+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-pod","depends_on_id":"hcs-y5a","type":"blocks","created_at":"2026-01-01T23:43:18.676898601+01:00","created_by":"gdiazlo"}]} 111 - {"id":"hcs-pwc","title":"Implement CODEC module signature","description":"Implement the CODEC module signature in hcs-core/codec.ml using buffers:\n\n```ocaml\nmodule type CODEC = sig\n type 'a encoder\n type 'a decoder\n\n val content_type : string (* e.g., \"application/json\", \"application/msgpack\" *)\n\n (* Use Cstruct.t for buffer-based encoding/decoding *)\n val encode : 'a encoder -\u003e 'a -\u003e (Cstruct.t, string) result\n val decode : 'a decoder -\u003e Cstruct.t -\u003e ('a, string) result\n \n (* Optional: streaming encode/decode for large payloads *)\n val encode_stream : 'a encoder -\u003e 'a -\u003e Cstruct.t Stream.t option\n val decode_stream : 'a decoder -\u003e Cstruct.t Stream.t -\u003e ('a, string) result option\nend\n```\n\nBenefits of buffer-based approach:\n- Zero-copy for binary formats (msgpack, protobuf, cbor)\n- Efficient for large payloads\n- Can still handle text formats (JSON) by converting at boundaries\n- Consistent with body type which uses Cstruct.t for streaming\n\nPure OCaml + cstruct, no runtime dependency.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:28:42.177976816+01:00","updated_at":"2025-12-29T17:04:22.669690697+01:00","closed_at":"2025-12-29T17:04:22.669690697+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-pwc","depends_on_id":"hcs-m4r","type":"parent-child","created_at":"2025-12-29T14:28:59.747767828+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-pwc","depends_on_id":"hcs-23f","type":"blocks","created_at":"2025-12-29T14:29:04.083986956+01:00","created_by":"gdiazlo"}]} 112 - {"id":"hcs-q4v","title":"LAS: Real-time updates (realtime.ml)","description":"Pubsub instance, broadcast_vote function, ws_handler for WebSocket subscriptions.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T23:41:57.42802297+01:00","updated_at":"2026-01-02T00:15:18.203793023+01:00","closed_at":"2026-01-02T00:15:18.203793023+01:00","dependencies":[{"issue_id":"hcs-q4v","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:53.486720346+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-q4v","depends_on_id":"hcs-gii","type":"blocks","created_at":"2026-01-01T23:43:38.846098179+01:00","created_by":"gdiazlo"}]} 113 - {"id":"hcs-qf7","title":"Implement radix trie for routing","description":"Implement radix trie in hcs-core/trie.ml:\n\n```ocaml\ntype 'a t\n\nval empty : 'a t\nval insert : Path.segment list -\u003e method_ -\u003e 'a -\u003e 'a t -\u003e 'a t\nval lookup : string list -\u003e method_ -\u003e 'a t -\u003e ('a * string list, string) result\n (* Returns handler and captured params *)\n\nval compile : 'a t -\u003e 'a t (* Optimize: compress edges, sort by priority *)\n```\n\nImplementation notes:\n- Radix trie with compressed edges for static segments\n- Parameter nodes stored separately for O(1) lookup\n- Method dispatch at leaf nodes (small array)\n- Priority: static \u003e typed param \u003e string param \u003e wildcard\n- Pre-compile regex for uuid validation\n\nPure OCaml, O(path_length) lookup.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:32:37.659665672+01:00","updated_at":"2025-12-29T15:18:02.267050922+01:00","closed_at":"2025-12-29T15:18:02.267050922+01:00","dependencies":[{"issue_id":"hcs-qf7","depends_on_id":"hcs-2ie","type":"parent-child","created_at":"2025-12-29T14:32:56.840281975+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-qf7","depends_on_id":"hcs-jsl","type":"blocks","created_at":"2025-12-29T14:32:57.708007508+01:00","created_by":"gdiazlo"}]} 114 - {"id":"hcs-qnb","title":"HTTP Client Implementation","description":"Implement the Client module with connection pooling, HTTP/1.1 and HTTP/2 support, request/fetch/stream methods, and configuration.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:28.006219271+01:00","updated_at":"2025-12-29T17:41:34.620441464+01:00","closed_at":"2025-12-29T17:41:34.620441464+01:00","dependencies":[{"issue_id":"hcs-qnb","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:11.475056322+01:00","created_by":"gdiazlo"}]} 115 - {"id":"hcs-ro3","title":"Add zlib and zstd to library dependencies","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:13.541332828+01:00","updated_at":"2026-01-01T18:47:23.510028123+01:00","closed_at":"2026-01-01T18:47:23.510028123+01:00"} 116 - {"id":"hcs-rvk","title":"Implement compress middleware that handles Accept-Encoding","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:18.99875834+01:00","updated_at":"2026-01-01T18:47:23.517194263+01:00","closed_at":"2026-01-01T18:47:23.517194263+01:00","dependencies":[{"issue_id":"hcs-rvk","depends_on_id":"hcs-gr3","type":"blocks","created_at":"2026-01-01T18:44:46.657521349+01:00","created_by":"gdiazlo"}]} 117 - {"id":"hcs-rw6","title":"HTTP Server Implementation","description":"Implement Server module with HTTP/1.1 and HTTP/2 support, configuration, graceful shutdown, and connection management.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:32.173329865+01:00","updated_at":"2025-12-29T17:41:35.435456001+01:00","closed_at":"2025-12-29T17:41:35.435456001+01:00","dependencies":[{"issue_id":"hcs-rw6","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:17.069517446+01:00","created_by":"gdiazlo"}]} 118 - {"id":"hcs-rzc","title":"HCS: Unified server with HTTP/1.1 + h2c upgrade + WebSocket","description":"Create single HCS server that detects protocol and routes to H1/H2/WS handlers. Support h2c upgrade from HTTP/1.1.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:31.15150333+01:00","updated_at":"2025-12-31T14:24:25.878899607+01:00","closed_at":"2025-12-31T14:24:25.878899607+01:00","dependencies":[{"issue_id":"hcs-rzc","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:25.89281292+01:00","created_by":"gdiazlo"}]} 119 - {"id":"hcs-s3a","title":"Implement runtime-specific middleware (Eio)","description":"Implement Eio-specific middleware in hcs-eio/middleware.ml:\n\n```ocaml\n(* Logging - needs clock for timing *)\nval logging : Eio.Time.clock -\u003e Log.logger -\u003e middleware\n\n(* Timeout *)\nval timeout : Eio.Time.clock -\u003e float -\u003e middleware\n\n(* Rate limiting - needs clock and mutable state *)\nval rate_limit :\n clock:Eio.Time.clock -\u003e\n key:(request -\u003e string) -\u003e\n requests:int -\u003e\n per:float -\u003e\n middleware\n\n(* Compression - CPU bound but may benefit from async *)\nval compress : ?level:int -\u003e ?min_size:int -\u003e unit -\u003e middleware\nval decompress : middleware\n\n(* Static files - needs filesystem *)\nval static :\n fs:Eio.Fs.dir_ty Eio.Path.t -\u003e\n ?index:string list -\u003e\n ?etag:bool -\u003e\n string -\u003e\n middleware\n\n(* ETag generation *)\nval etag : middleware\nval cache_control : string -\u003e middleware\n```","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:31.955254986+01:00","updated_at":"2025-12-29T17:14:15.252061602+01:00","closed_at":"2025-12-29T17:14:15.252061602+01:00","dependencies":[{"issue_id":"hcs-s3a","depends_on_id":"hcs-3ww","type":"parent-child","created_at":"2025-12-29T14:34:51.261233247+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-s3a","depends_on_id":"hcs-bea","type":"blocks","created_at":"2025-12-29T14:34:57.261423006+01:00","created_by":"gdiazlo"}]} 120 - {"id":"hcs-s94","title":"Rust: Unified Hyper server with HTTP/1.1 + h2c + WebSocket","description":"Update Hyper server to handle HTTP/1.1, h2c, and WebSocket on single port.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:41.231763861+01:00","updated_at":"2025-12-31T14:31:18.83450995+01:00","closed_at":"2025-12-31T14:31:18.83450995+01:00","dependencies":[{"issue_id":"hcs-s94","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:35.978086083+01:00","created_by":"gdiazlo"}]} 121 - {"id":"hcs-sby","title":"Add type documentation clarifying Middleware.t relationship","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T18:15:16.616774958+01:00","updated_at":"2026-01-01T18:16:50.859523483+01:00","closed_at":"2026-01-01T18:16:50.859523483+01:00"} 122 - {"id":"hcs-sny","title":"Implement Router module","description":"Implement router API in hcs-core/router.ml:\n\n```ocaml\ntype 'a handler = 'a -\u003e request -\u003e (response, error) result\ntype middleware = (request -\u003e (response, error) result) -\u003e request -\u003e (response, error) result\n\ntype t\n\n(* Route registration *)\nval get : 'a Path.t -\u003e 'a handler -\u003e t\nval post : 'a Path.t -\u003e 'a handler -\u003e t\nval put : 'a Path.t -\u003e 'a handler -\u003e t\nval delete : 'a Path.t -\u003e 'a handler -\u003e t\nval patch : 'a Path.t -\u003e 'a handler -\u003e t\nval head : 'a Path.t -\u003e 'a handler -\u003e t\nval options : 'a Path.t -\u003e 'a handler -\u003e t\nval any : method_ list -\u003e 'a Path.t -\u003e 'a handler -\u003e t\n\n(* Composition *)\nval routes : t list -\u003e t\nval scope : string -\u003e t list -\u003e t\nval scope_with : string -\u003e middleware list -\u003e t list -\u003e t\nval with_middleware : middleware list -\u003e t -\u003e t\n\n(* Compilation *)\ntype compiled\nval compile : t -\u003e compiled\nval match_ : compiled -\u003e request -\u003e (response, error) result\n```\n\nPure OCaml, builds on Path and Trie.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:32:43.527248631+01:00","updated_at":"2025-12-29T15:18:03.419090442+01:00","closed_at":"2025-12-29T15:18:03.419090442+01:00","dependencies":[{"issue_id":"hcs-sny","depends_on_id":"hcs-2ie","type":"parent-child","created_at":"2025-12-29T14:32:57.378211329+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-sny","depends_on_id":"hcs-qf7","type":"blocks","created_at":"2025-12-29T14:32:58.327421433+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-sny","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:32:59.27491603+01:00","created_by":"gdiazlo"}]} 123 - {"id":"hcs-tn3","title":"Run WebSocket benchmarks and collect results","description":"Execute the benchmark suite, collect memory and connection data, document findings.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T10:00:04.76879529+01:00","updated_at":"2025-12-30T10:22:46.346637622+01:00","closed_at":"2025-12-30T10:22:46.346637622+01:00","dependencies":[{"issue_id":"hcs-tn3","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:50.758778716+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-tn3","depends_on_id":"hcs-wkv","type":"blocks","created_at":"2025-12-30T10:01:15.964007648+01:00","created_by":"gdiazlo"}]} 124 - {"id":"hcs-tzc","title":"Implement Server.config type","description":"Implement server configuration in hcs-core/server_config.ml:\n\n```ocaml\ntype config = {\n host : string; (* default: \"0.0.0.0\" *)\n port : int; (* default: 8080 *)\n backlog : int; (* default: 2048 *)\n max_connections : int; (* default: 10000 *)\n\n (* Timeouts *)\n read_timeout : float; (* default: 60.0 *)\n write_timeout : float; (* default: 60.0 *)\n idle_timeout : float; (* default: 120.0 *)\n request_timeout : float; (* default: 30.0 *)\n\n (* Limits *)\n max_header_size : int; (* default: 8192 *)\n max_body_size : int64 option; (* None = unlimited *)\n\n (* Protocol *)\n http2 : bool; (* default: true *)\n buffer_size : int; (* default: 16384 *)\n\n (* TLS *)\n tls : Tls_config.server option;\n\n (* Compression *)\n compress_response : bool; (* default: true *)\n compression_min_size : int; (* default: 1024 *)\n compression_level : int; (* default: 6 *)\n\n (* Logging *)\n logger : Log.logger;\n}\n\nval default : config\n```\n\nPure configuration, no IO.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:15.561446445+01:00","updated_at":"2025-12-29T15:40:25.769211668+01:00","closed_at":"2025-12-29T15:40:25.769211668+01:00","dependencies":[{"issue_id":"hcs-tzc","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:40.219574299+01:00","created_by":"gdiazlo"}]} 125 - {"id":"hcs-ucw","title":"Implement Response helper module","description":"Implement response helpers in hcs-core/response.ml:\n\n```ocaml\nval make : ?version:version -\u003e ?headers:Headers.t -\u003e ?body:body -\u003e status -\u003e response\n\n(* Status shortcuts *)\nval ok : ?headers:Headers.t -\u003e body -\u003e response\nval created : ?headers:Headers.t -\u003e ?location:string -\u003e body -\u003e response\nval no_content : unit -\u003e response\nval bad_request : ?body:body -\u003e unit -\u003e response\nval unauthorized : ?www_authenticate:string -\u003e unit -\u003e response\nval forbidden : ?body:body -\u003e unit -\u003e response\nval not_found : ?body:body -\u003e unit -\u003e response\nval method_not_allowed : allowed:method_ list -\u003e unit -\u003e response\nval internal_error : ?body:body -\u003e unit -\u003e response\n(* ... all status helpers from spec ... *)\n\n(* Body helpers *)\nval text : string -\u003e response\nval html : string -\u003e response\nval redirect : ?permanent:bool -\u003e string -\u003e response\n\n(* Modify response *)\nval with_header : string -\u003e string -\u003e response -\u003e response\nval with_headers : (string * string) list -\u003e response -\u003e response\nval with_body : body -\u003e response -\u003e response\n```\n\nPure OCaml.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:34:17.870074295+01:00","updated_at":"2025-12-29T15:40:30.579234447+01:00","closed_at":"2025-12-29T15:40:30.579234447+01:00","dependencies":[{"issue_id":"hcs-ucw","depends_on_id":"hcs-dle","type":"parent-child","created_at":"2025-12-29T14:34:48.628725792+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-ucw","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:34:55.629240942+01:00","created_by":"gdiazlo"}]} 126 - {"id":"hcs-ugs","title":"Core Types and Foundations","description":"Implement core type foundations: method_, version, status, Headers module, body type, request/response records, and error types.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:19.301411166+01:00","updated_at":"2025-12-29T15:42:11.485073934+01:00","closed_at":"2025-12-29T15:42:11.485073934+01:00","dependencies":[{"issue_id":"hcs-ugs","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:25:54.989012647+01:00","created_by":"gdiazlo"}]} 129 + {"id":"hcs-lhr","title":"WebSocket Support","description":"Implement Ws module with frame types, connection management, send/recv operations, server upgrade handler, and client connect.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:36.29066838+01:00","updated_at":"2025-12-29T16:01:05.272490486+01:00","closed_at":"2025-12-29T16:01:05.272490486+01:00","dependencies":[{"issue_id":"hcs-lhr","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:20.036599039+01:00","created_by":"gdiazlo","metadata":"{}"}]} 130 + {"id":"hcs-llr","title":"Implement Rust/hyper benchmark server (plaintext + json, HTTP/1+2, CPU scaling)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T22:21:26.556966252+01:00","updated_at":"2025-12-30T22:28:28.337697653+01:00","closed_at":"2025-12-30T22:28:28.337697653+01:00"} 131 + {"id":"hcs-lpr","title":"Implement request and response record types","description":"Implement request and response records in types.ml:\n\n```ocaml\ntype request = {\n meth : method_;\n uri : Uri.t;\n version : version;\n headers : Headers.t;\n body : body;\n}\n\ntype response = {\n status : status;\n version : version;\n headers : Headers.t;\n body : body;\n}\n```\n\nInclude smart constructors and accessors. Pure OCaml + uri package.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:27:19.295375903+01:00","updated_at":"2025-12-29T14:50:46.801981182+01:00","closed_at":"2025-12-29T14:50:46.801981182+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-lpr","depends_on_id":"hcs-ugs","type":"blocks","created_at":"2025-12-29T14:27:19.300960037+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-6yl","type":"blocks","created_at":"2025-12-29T14:27:43.920564401+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-cmg","type":"blocks","created_at":"2025-12-29T14:27:44.815114113+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-cks","type":"blocks","created_at":"2025-12-29T14:27:45.656483969+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-lpr","depends_on_id":"hcs-chm","type":"blocks","created_at":"2025-12-29T14:27:46.481924426+01:00","created_by":"gdiazlo","metadata":"{}"}]} 132 + {"id":"hcs-lqi","title":"Implement HTTP/1.1 server (Eio)","description":"Implement HTTP/1.1 server for Eio in hcs-eio/h1_server.ml:\n\n```ocaml\nval handle_connection :\n flow:Eio.Flow.two_way -\u003e\n clock:Eio.Time.clock -\u003e\n config:Server.config -\u003e\n handler:(request -\u003e (response, error) result) -\u003e\n unit\n```\n\nFeatures:\n- Parse requests using h1 parser\n- Handle keep-alive connections\n- Support chunked and fixed-length bodies\n- Respect timeouts\n- Handle pipelining (optional)\n- Integrate with logging","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:22.560229088+01:00","updated_at":"2025-12-29T15:03:24.765221644+01:00","closed_at":"2025-12-29T15:03:24.765221644+01:00","dependencies":[{"issue_id":"hcs-lqi","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:42.102983428+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-lqi","depends_on_id":"hcs-56z","type":"blocks","created_at":"2025-12-29T14:33:44.325287786+01:00","created_by":"gdiazlo","metadata":"{}"}]} 133 + {"id":"hcs-lskj","title":"Update: Export App module in hcs.ml","description":"Update lib/hcs.ml:\n- Add: module App = App\n- Keep: module Endpoint = App (deprecated alias for backward compat)\n- Update docstrings to reflect new design\n- Add deprecation notice for Endpoint","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T20:59:43.868501712+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:11:18.247236619+01:00","closed_at":"2026-01-03T21:11:18.247236619+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-lskj","depends_on_id":"hcs-pcri","type":"blocks","created_at":"2026-01-03T21:00:22.904885823+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-lskj","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:29.635048148+01:00","created_by":"gdiazlo"}]} 134 + {"id":"hcs-lsmn","title":"Docs: Update documentation for v0.2.0","description":"Update all documentation:\n\n1. README.md - update architecture section, add pipeline examples\n2. bin/las/README.md - update tutorial with new API\n3. Add CHANGELOG.md with breaking changes\n4. Add migration guide from 0.1.x to 0.2.0\n5. Document the three-layer plug model","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-03T21:12:16.403916721+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:12:16.403916721+01:00","dependencies":[{"issue_id":"hcs-lsmn","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:13:19.833264053+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-lsmn","depends_on_id":"hcs-7neb","type":"blocks","created_at":"2026-01-03T21:14:30.606697175+01:00","created_by":"gdiazlo"}]} 135 + {"id":"hcs-m4r","title":"Codec System","description":"Implement the functor-based CODEC signature and With_codec functor for type-safe serialization/deserialization. Use Cstruct.t (buffers) instead of strings to properly support binary formats like MessagePack, Protobuf, and CBOR.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:22.203715886+01:00","updated_at":"2025-12-29T17:40:46.982752973+01:00","closed_at":"2025-12-29T17:40:46.982752973+01:00","dependencies":[{"issue_id":"hcs-m4r","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:00.496780385+01:00","created_by":"gdiazlo","metadata":"{}"}]} 136 + {"id":"hcs-mip","title":"Implement Http request builder DSL","description":"Implement high-level client DSL in hcs-core/http.ml:\n\n```ocaml\ntype builder\n\nval get : string -\u003e (builder, error) result\nval post : string -\u003e (builder, error) result\nval put : string -\u003e (builder, error) result\nval delete : string -\u003e (builder, error) result\n(* ... other methods ... *)\n\nval of_uri : method_ -\u003e Uri.t -\u003e builder\n\n(* Headers *)\nval header : string -\u003e string -\u003e builder -\u003e builder\nval headers : (string * string) list -\u003e builder -\u003e builder\nval content_type : string -\u003e builder -\u003e builder\nval accept : string -\u003e builder -\u003e builder\nval bearer : string -\u003e builder -\u003e builder\nval basic_auth : user:string -\u003e pass:string -\u003e builder -\u003e builder\nval user_agent : string -\u003e builder -\u003e builder\n\n(* Query parameters *)\nval query : string -\u003e string -\u003e builder -\u003e builder\nval queries : (string * string) list -\u003e builder -\u003e builder\n\n(* Body *)\nval body : body -\u003e builder -\u003e builder\nval body_string : ?content_type:string -\u003e string -\u003e builder -\u003e builder\nval form : (string * string) list -\u003e builder -\u003e builder\n\n(* Build final request *)\nval build : builder -\u003e request\n```\n\nPure OCaml, no IO.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:22.698743046+01:00","updated_at":"2025-12-29T17:10:04.149286655+01:00","closed_at":"2025-12-29T17:10:04.149286655+01:00","dependencies":[{"issue_id":"hcs-mip","depends_on_id":"hcs-l23","type":"parent-child","created_at":"2025-12-29T14:34:49.5612417+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-mip","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:34:56.47577088+01:00","created_by":"gdiazlo","metadata":"{}"}]} 137 + {"id":"hcs-mjh","title":"Diagnose SSE respond_stream closes immediately; fix; add regression tests proving streaming works","status":"closed","priority":0,"issue_type":"bug","created_at":"2026-01-02T14:57:27.955502878+01:00","updated_at":"2026-01-03T11:14:59.327782781+01:00","closed_at":"2026-01-03T11:14:59.327782781+01:00"} 138 + {"id":"hcs-mli","title":"Run multi-CPU benchmarks (4, 8, 16 CPUs)","description":"Run benchmarks with 4, 8, and 16 domains for HCS, compare with Rust and Go multi-threaded.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:59.450548339+01:00","updated_at":"2025-12-30T09:16:49.37792589+01:00","closed_at":"2025-12-30T09:16:49.37792589+01:00","dependencies":[{"issue_id":"hcs-mli","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:29.226366436+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-mli","depends_on_id":"hcs-zln","type":"blocks","created_at":"2025-12-30T09:06:44.348550935+01:00","created_by":"gdiazlo","metadata":"{}"}]} 139 + {"id":"hcs-mnm","title":"docs: WebSocket guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:46.079959801+01:00","updated_at":"2026-01-03T01:03:23.148320714+01:00","closed_at":"2026-01-03T01:03:23.148320714+01:00"} 140 + {"id":"hcs-nad","title":"Implement WebSocket connection (Eio)","description":"Implement WebSocket for Eio in hcs-eio/websocket.ml:\n\n```ocaml\ntype conn\n\nval is_open : conn -\u003e bool\n\n(* Receive *)\nval recv : conn -\u003e (frame option, error) result\nval recv_timeout : Eio.Time.clock -\u003e float -\u003e conn -\u003e (frame option, error) result\n\n(* Send *)\nval send : conn -\u003e frame -\u003e (unit, error) result\nval close : ?code:int -\u003e ?reason:string -\u003e conn -\u003e (unit, error) result\n\n(* Stream interface *)\nval recv_stream : conn -\u003e frame Stream.t\nval send_stream : conn -\u003e frame Stream.t -\u003e (unit, error) result\n\n(* Server: upgrade handler *)\nval upgrade :\n ?protocols:string list -\u003e\n ?on_close:(int option -\u003e string option -\u003e unit) -\u003e\n (conn -\u003e (unit, error) result) -\u003e\n unit handler\n\n(* Client: connect *)\nval connect :\n sw:Eio.Switch.t -\u003e\n net:Eio.Net.t -\u003e\n clock:Eio.Time.clock -\u003e\n ?tls:Tls_config.client -\u003e\n ?headers:Headers.t -\u003e\n ?protocols:string list -\u003e\n string -\u003e\n (conn, error) result\n```","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:33.686889707+01:00","updated_at":"2025-12-29T16:00:45.086724651+01:00","closed_at":"2025-12-29T16:00:45.086724651+01:00","dependencies":[{"issue_id":"hcs-nad","depends_on_id":"hcs-lhr","type":"parent-child","created_at":"2025-12-29T14:34:52.929848888+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-nad","depends_on_id":"hcs-0ro","type":"blocks","created_at":"2025-12-29T14:34:58.053806421+01:00","created_by":"gdiazlo","metadata":"{}"}]} 141 + {"id":"hcs-njk","title":"Run HTTP/2 comparison benchmarks and analyze results","description":"Execute the HTTP/2 benchmarks across all three implementations. Collect req/s, latency (p50/p99), memory usage. Document results in BENCHMARKS.md with analysis of performance characteristics.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T08:21:59.417171367+01:00","updated_at":"2025-12-30T08:48:51.035410704+01:00","closed_at":"2025-12-30T08:48:51.035410704+01:00","dependencies":[{"issue_id":"hcs-njk","depends_on_id":"hcs-ddd","type":"blocks","created_at":"2025-12-30T08:22:17.716250574+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-njk","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:28.307104582+01:00","created_by":"gdiazlo","metadata":"{}"}]} 142 + {"id":"hcs-nwb","title":"LAS: Route definitions (routes.ml)","description":"Router.compile with all routes. Apply content negotiation to appropriate endpoints. Rate limit submissions.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:47.344395357+01:00","updated_at":"2026-01-02T10:27:11.186653396+01:00","closed_at":"2026-01-02T10:27:11.186653396+01:00","dependencies":[{"issue_id":"hcs-nwb","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:43.416555822+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-nwb","depends_on_id":"hcs-yg6","type":"blocks","created_at":"2026-01-01T23:43:43.888397319+01:00","created_by":"gdiazlo","metadata":"{}"}]} 143 + {"id":"hcs-oo5","title":"Benchmark suite: single-CPU comparison of HCS, hyper, fasthttp","notes":"## Benchmark Results (Dec 31, 2025)\n\n### HCS vs Eio Native (c=1000, 100k requests)\n\n| Domains | HCS run_parallel | Eio run_server | Winner |\n|---------|------------------|----------------|--------|\n| 1 | 142k | 136k | HCS +4% |\n| 2 | 196k | 200k | Eio +2% |\n| 4 | 264k | 259k | HCS +2% |\n| 8 | 259k | 267k | Eio +3% |\n\n**Key Finding**: Both approaches perform similarly. The 2-domain regression previously observed was a measurement artifact.\n\n### HCS vs Fasthttp (c=1000, 100k requests)\n\n| Domains | HCS | Fasthttp | Winner |\n|---------|-----|----------|--------|\n| 1 | 137k | 181k | Fasthttp +32% |\n| 4 | 242k | 186k | **HCS +30%** |\n| 8 | 228k | 204k | **HCS +12%** |\n\n**Key Finding**: HCS scales BETTER than Fasthttp and beats it at 4+ domains!\n\n### Conclusions\n\n1. The nested `Eio_main.run` is NOT a problem - Eio's Domain_manager.run does the same thing internally\n2. SO_REUSEPORT (HCS) vs shared socket (Eio native) perform similarly - no clear winner\n3. HCS multi-core scaling is actually quite good - beats Fasthttp at higher core counts\n4. Earlier \"2-domain regression\" was likely a measurement artifact (port reuse, warmup, etc.)\n\n### Remaining Optimization Opportunities\n\n1. Single-core performance still lags Fasthttp by ~32% - room for improvement in request parsing/response writing\n2. 8-domain shows slight regression from 4-domain for HCS - could investigate GC tuning\n3. Hyper benchmark failed to run - need to fix for comparison","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-30T22:41:13.187711389+01:00","updated_at":"2025-12-31T09:33:51.051037492+01:00","closed_at":"2025-12-31T09:33:51.051037492+01:00"} 144 + {"id":"hcs-oqc","title":"Implement signed/encrypted Tokens","description":"Signed and encrypted tokens for auth, password reset, email verification.\n\n## Design\n\n### Core API\n```ocaml\nmodule Token : sig\n type t\n \n val sign : secret:string -\u003e data:string -\u003e max_age:float -\u003e string\n val verify : secret:string -\u003e token:string -\u003e (string, error) result\n \n val encrypt : secret:string -\u003e data:string -\u003e max_age:float -\u003e string \n val decrypt : secret:string -\u003e token:string -\u003e (string, error) result\nend\n```\n\n### Token Format\n```\nsigned: base64(data) . timestamp . base64(hmac)\nencrypted: base64(nonce + ciphertext + tag) . timestamp . base64(hmac)\n```\n\n### Implementation\n- Use existing `digestif` for HMAC-SHA256\n- Use existing `mirage-crypto` for AES-GCM encryption\n- Timestamp encoded as varint for compactness\n- Single allocation for final token string\n\n### Use Cases\n```ocaml\n(* Auth token *)\nlet token = Token.sign ~secret ~data:user_id ~max_age:86400.0\n\n(* Password reset - encrypted so user can't see payload *)\nlet token = Token.encrypt ~secret ~data:user_id ~max_age:3600.0\n\n(* Verify *)\nmatch Token.verify ~secret token with\n| Ok user_id -\u003e ...\n| Error Token.Expired -\u003e ...\n| Error Token.Invalid -\u003e ...\n```\n\n### Performance\n- No JSON parsing, raw bytes\n- Constant-time comparison for signatures\n- Reuse crypto contexts where possible","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T20:47:03.67375632+01:00","updated_at":"2026-01-01T21:07:48.604332258+01:00","closed_at":"2026-01-01T21:07:48.604332258+01:00","dependencies":[{"issue_id":"hcs-oqc","depends_on_id":"hcs-1op","type":"parent-child","created_at":"2026-01-01T20:47:56.644986614+01:00","created_by":"gdiazlo","metadata":"{}"}]} 145 + {"id":"hcs-osg","title":"Create Rust HTTP/2 benchmark server (hyper)","description":"Implement a Rust HTTP/2 server using hyper with h2c (cleartext HTTP/2) support. Match endpoints: /ping, /bytes/:n, /json. Use tokio runtime, pre-allocate response buffers for zero-copy.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T08:21:52.194368992+01:00","updated_at":"2025-12-30T08:48:32.166538953+01:00","closed_at":"2025-12-30T08:48:32.166538953+01:00","dependencies":[{"issue_id":"hcs-osg","depends_on_id":"hcs-82y","type":"parent-child","created_at":"2025-12-30T08:22:20.416305094+01:00","created_by":"gdiazlo","metadata":"{}"}]} 146 + {"id":"hcs-pcri","title":"Implement: Create App module from Endpoint","description":"Create lib/app.ml with:\n- Rename Endpoint → App\n- Remove server config fields (port, bind, domains, protocol, tls)\n- Keep only: secret_key_base, health_check\n- Update App.start to accept Server.config as parameter\n- Keep: plug, router, websocket, build_handler functions\n\nMust preserve all existing functionality.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T20:59:36.516811197+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:11:03.08414908+01:00","closed_at":"2026-01-03T21:11:03.08414908+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-pcri","depends_on_id":"hcs-yppn","type":"blocks","created_at":"2026-01-03T21:00:07.735011115+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-pcri","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:14.468743555+01:00","created_by":"gdiazlo"}]} 147 + {"id":"hcs-peu","title":"HCS benchmark client: HTTP/1.1 + HTTP/2 + WebSocket support","description":"Create comprehensive benchmark client supporting all protocols with connection reuse, multiplexing, and WebSocket message throughput.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:46.273123556+01:00","updated_at":"2025-12-31T14:37:50.862757453+01:00","closed_at":"2025-12-31T14:37:50.862757453+01:00","dependencies":[{"issue_id":"hcs-peu","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:41.0222415+01:00","created_by":"gdiazlo","metadata":"{}"}]} 148 + {"id":"hcs-pnc","title":"Control Flow and Cancellation","description":"Implement Cancel module for cooperative cancellation and Control module for timeout, retry, deadline, and circuit breaker patterns.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:23.840150584+01:00","updated_at":"2025-12-29T15:41:49.225247023+01:00","closed_at":"2025-12-29T15:41:49.225247023+01:00","dependencies":[{"issue_id":"hcs-pnc","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:03.266144948+01:00","created_by":"gdiazlo","metadata":"{}"}]} 149 + {"id":"hcs-pod","title":"LAS: HTML views (views.ml)","description":"Layout template, link list, link detail, login/register forms, submit form. Include CSRF tokens in forms.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T23:41:42.302380219+01:00","updated_at":"2026-01-01T23:55:18.489268725+01:00","closed_at":"2026-01-01T23:55:18.489268725+01:00","dependencies":[{"issue_id":"hcs-pod","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:38.379707386+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-pod","depends_on_id":"hcs-y5a","type":"blocks","created_at":"2026-01-01T23:43:18.676898601+01:00","created_by":"gdiazlo","metadata":"{}"}]} 150 + {"id":"hcs-pwc","title":"Implement CODEC module signature","description":"Implement the CODEC module signature in hcs-core/codec.ml using buffers:\n\n```ocaml\nmodule type CODEC = sig\n type 'a encoder\n type 'a decoder\n\n val content_type : string (* e.g., \"application/json\", \"application/msgpack\" *)\n\n (* Use Cstruct.t for buffer-based encoding/decoding *)\n val encode : 'a encoder -\u003e 'a -\u003e (Cstruct.t, string) result\n val decode : 'a decoder -\u003e Cstruct.t -\u003e ('a, string) result\n \n (* Optional: streaming encode/decode for large payloads *)\n val encode_stream : 'a encoder -\u003e 'a -\u003e Cstruct.t Stream.t option\n val decode_stream : 'a decoder -\u003e Cstruct.t Stream.t -\u003e ('a, string) result option\nend\n```\n\nBenefits of buffer-based approach:\n- Zero-copy for binary formats (msgpack, protobuf, cbor)\n- Efficient for large payloads\n- Can still handle text formats (JSON) by converting at boundaries\n- Consistent with body type which uses Cstruct.t for streaming\n\nPure OCaml + cstruct, no runtime dependency.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:28:42.177976816+01:00","updated_at":"2025-12-29T17:04:22.669690697+01:00","closed_at":"2025-12-29T17:04:22.669690697+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-pwc","depends_on_id":"hcs-m4r","type":"parent-child","created_at":"2025-12-29T14:28:59.747767828+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-pwc","depends_on_id":"hcs-23f","type":"blocks","created_at":"2025-12-29T14:29:04.083986956+01:00","created_by":"gdiazlo","metadata":"{}"}]} 151 + {"id":"hcs-q4v","title":"LAS: Real-time updates (realtime.ml)","description":"Pubsub instance, broadcast_vote function, ws_handler for WebSocket subscriptions.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T23:41:57.42802297+01:00","updated_at":"2026-01-03T11:18:17.251364679+01:00","closed_at":"2026-01-03T11:18:17.251364679+01:00","dependencies":[{"issue_id":"hcs-q4v","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:53.486720346+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-q4v","depends_on_id":"hcs-gii","type":"blocks","created_at":"2026-01-01T23:43:38.846098179+01:00","created_by":"gdiazlo","metadata":"{}"}]} 152 + {"id":"hcs-qf7","title":"Implement radix trie for routing","description":"Implement radix trie in hcs-core/trie.ml:\n\n```ocaml\ntype 'a t\n\nval empty : 'a t\nval insert : Path.segment list -\u003e method_ -\u003e 'a -\u003e 'a t -\u003e 'a t\nval lookup : string list -\u003e method_ -\u003e 'a t -\u003e ('a * string list, string) result\n (* Returns handler and captured params *)\n\nval compile : 'a t -\u003e 'a t (* Optimize: compress edges, sort by priority *)\n```\n\nImplementation notes:\n- Radix trie with compressed edges for static segments\n- Parameter nodes stored separately for O(1) lookup\n- Method dispatch at leaf nodes (small array)\n- Priority: static \u003e typed param \u003e string param \u003e wildcard\n- Pre-compile regex for uuid validation\n\nPure OCaml, O(path_length) lookup.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:32:37.659665672+01:00","updated_at":"2025-12-29T15:18:02.267050922+01:00","closed_at":"2025-12-29T15:18:02.267050922+01:00","dependencies":[{"issue_id":"hcs-qf7","depends_on_id":"hcs-2ie","type":"parent-child","created_at":"2025-12-29T14:32:56.840281975+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-qf7","depends_on_id":"hcs-jsl","type":"blocks","created_at":"2025-12-29T14:32:57.708007508+01:00","created_by":"gdiazlo","metadata":"{}"}]} 153 + {"id":"hcs-qio9","title":"Update: Export new modules in hcs.ml","description":"Update lib/hcs.ml:\n\n1. Add: module Pipeline = Pipeline\n2. Update Endpoint docstring\n3. Update Router docstring to mention scopes/pipelines\n4. Ensure backward compat where possible","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:12:11.052621796+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:31:15.956731098+01:00","closed_at":"2026-01-03T21:31:15.956731098+01:00","close_reason":"Updated exports","dependencies":[{"issue_id":"hcs-qio9","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:13:09.729981814+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-qio9","depends_on_id":"hcs-ty6r","type":"blocks","created_at":"2026-01-03T21:14:10.38855906+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-qio9","depends_on_id":"hcs-cf24","type":"blocks","created_at":"2026-01-03T21:14:15.445981728+01:00","created_by":"gdiazlo"}]} 154 + {"id":"hcs-qnb","title":"HTTP Client Implementation","description":"Implement the Client module with connection pooling, HTTP/1.1 and HTTP/2 support, request/fetch/stream methods, and configuration.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:28.006219271+01:00","updated_at":"2025-12-29T17:41:34.620441464+01:00","closed_at":"2025-12-29T17:41:34.620441464+01:00","dependencies":[{"issue_id":"hcs-qnb","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:11.475056322+01:00","created_by":"gdiazlo","metadata":"{}"}]} 155 + {"id":"hcs-rjd","title":"LAS SSE: /events always 401 because htmx-ext-sse doesn't send session cookie","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-02T14:26:24.087928897+01:00","updated_at":"2026-01-03T11:17:38.9260436+01:00","closed_at":"2026-01-03T11:17:38.9260436+01:00"} 156 + {"id":"hcs-ro3","title":"Add zlib and zstd to library dependencies","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:13.541332828+01:00","updated_at":"2026-01-01T18:47:23.510028123+01:00","closed_at":"2026-01-01T18:47:23.510028123+01:00"} 157 + {"id":"hcs-rue0","title":"docs: TLS Configuration guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:45:07.097801761+01:00","updated_at":"2026-01-03T11:53:57.110263077+01:00","closed_at":"2026-01-03T11:53:57.110263077+01:00"} 158 + {"id":"hcs-rvk","title":"Implement compress middleware that handles Accept-Encoding","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:44:18.99875834+01:00","updated_at":"2026-01-01T18:47:23.517194263+01:00","closed_at":"2026-01-01T18:47:23.517194263+01:00","dependencies":[{"issue_id":"hcs-rvk","depends_on_id":"hcs-gr3","type":"blocks","created_at":"2026-01-01T18:44:46.657521349+01:00","created_by":"gdiazlo","metadata":"{}"}]} 159 + {"id":"hcs-rw6","title":"HTTP Server Implementation","description":"Implement Server module with HTTP/1.1 and HTTP/2 support, configuration, graceful shutdown, and connection management.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:32.173329865+01:00","updated_at":"2025-12-29T17:41:35.435456001+01:00","closed_at":"2025-12-29T17:41:35.435456001+01:00","dependencies":[{"issue_id":"hcs-rw6","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:17.069517446+01:00","created_by":"gdiazlo","metadata":"{}"}]} 160 + {"id":"hcs-rzc","title":"HCS: Unified server with HTTP/1.1 + h2c upgrade + WebSocket","description":"Create single HCS server that detects protocol and routes to H1/H2/WS handlers. Support h2c upgrade from HTTP/1.1.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:31.15150333+01:00","updated_at":"2025-12-31T14:24:25.878899607+01:00","closed_at":"2025-12-31T14:24:25.878899607+01:00","dependencies":[{"issue_id":"hcs-rzc","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:25.89281292+01:00","created_by":"gdiazlo","metadata":"{}"}]} 161 + {"id":"hcs-s3a","title":"Implement runtime-specific middleware (Eio)","description":"Implement Eio-specific middleware in hcs-eio/middleware.ml:\n\n```ocaml\n(* Logging - needs clock for timing *)\nval logging : Eio.Time.clock -\u003e Log.logger -\u003e middleware\n\n(* Timeout *)\nval timeout : Eio.Time.clock -\u003e float -\u003e middleware\n\n(* Rate limiting - needs clock and mutable state *)\nval rate_limit :\n clock:Eio.Time.clock -\u003e\n key:(request -\u003e string) -\u003e\n requests:int -\u003e\n per:float -\u003e\n middleware\n\n(* Compression - CPU bound but may benefit from async *)\nval compress : ?level:int -\u003e ?min_size:int -\u003e unit -\u003e middleware\nval decompress : middleware\n\n(* Static files - needs filesystem *)\nval static :\n fs:Eio.Fs.dir_ty Eio.Path.t -\u003e\n ?index:string list -\u003e\n ?etag:bool -\u003e\n string -\u003e\n middleware\n\n(* ETag generation *)\nval etag : middleware\nval cache_control : string -\u003e middleware\n```","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-29T14:34:31.955254986+01:00","updated_at":"2025-12-29T17:14:15.252061602+01:00","closed_at":"2025-12-29T17:14:15.252061602+01:00","dependencies":[{"issue_id":"hcs-s3a","depends_on_id":"hcs-3ww","type":"parent-child","created_at":"2025-12-29T14:34:51.261233247+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-s3a","depends_on_id":"hcs-bea","type":"blocks","created_at":"2025-12-29T14:34:57.261423006+01:00","created_by":"gdiazlo","metadata":"{}"}]} 162 + {"id":"hcs-s6ii","title":"Optimize SSE event formatting to avoid per-event string allocation","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T11:32:29.951052367+01:00","updated_at":"2026-01-03T11:37:50.157773361+01:00","closed_at":"2026-01-03T11:37:50.157773361+01:00"} 163 + {"id":"hcs-s94","title":"Rust: Unified Hyper server with HTTP/1.1 + h2c + WebSocket","description":"Update Hyper server to handle HTTP/1.1, h2c, and WebSocket on single port.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-31T14:13:41.231763861+01:00","updated_at":"2025-12-31T14:31:18.83450995+01:00","closed_at":"2025-12-31T14:31:18.83450995+01:00","dependencies":[{"issue_id":"hcs-s94","depends_on_id":"hcs-5wp","type":"parent-child","created_at":"2025-12-31T14:14:35.978086083+01:00","created_by":"gdiazlo","metadata":"{}"}]} 164 + {"id":"hcs-sby","title":"Add type documentation clarifying Middleware.t relationship","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-01T18:15:16.616774958+01:00","updated_at":"2026-01-01T18:16:50.859523483+01:00","closed_at":"2026-01-01T18:16:50.859523483+01:00"} 165 + {"id":"hcs-sl6","title":"docs: First Server guide","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T00:44:23.401637373+01:00","updated_at":"2026-01-03T00:49:50.871335442+01:00","closed_at":"2026-01-03T00:49:50.871335442+01:00","dependencies":[{"issue_id":"hcs-sl6","depends_on_id":"hcs-vjo","type":"blocks","created_at":"2026-01-03T00:45:29.340153964+01:00","created_by":"gdiazlo","metadata":"{}"}]} 166 + {"id":"hcs-sny","title":"Implement Router module","description":"Implement router API in hcs-core/router.ml:\n\n```ocaml\ntype 'a handler = 'a -\u003e request -\u003e (response, error) result\ntype middleware = (request -\u003e (response, error) result) -\u003e request -\u003e (response, error) result\n\ntype t\n\n(* Route registration *)\nval get : 'a Path.t -\u003e 'a handler -\u003e t\nval post : 'a Path.t -\u003e 'a handler -\u003e t\nval put : 'a Path.t -\u003e 'a handler -\u003e t\nval delete : 'a Path.t -\u003e 'a handler -\u003e t\nval patch : 'a Path.t -\u003e 'a handler -\u003e t\nval head : 'a Path.t -\u003e 'a handler -\u003e t\nval options : 'a Path.t -\u003e 'a handler -\u003e t\nval any : method_ list -\u003e 'a Path.t -\u003e 'a handler -\u003e t\n\n(* Composition *)\nval routes : t list -\u003e t\nval scope : string -\u003e t list -\u003e t\nval scope_with : string -\u003e middleware list -\u003e t list -\u003e t\nval with_middleware : middleware list -\u003e t -\u003e t\n\n(* Compilation *)\ntype compiled\nval compile : t -\u003e compiled\nval match_ : compiled -\u003e request -\u003e (response, error) result\n```\n\nPure OCaml, builds on Path and Trie.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:32:43.527248631+01:00","updated_at":"2025-12-29T15:18:03.419090442+01:00","closed_at":"2025-12-29T15:18:03.419090442+01:00","dependencies":[{"issue_id":"hcs-sny","depends_on_id":"hcs-2ie","type":"parent-child","created_at":"2025-12-29T14:32:57.378211329+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-sny","depends_on_id":"hcs-qf7","type":"blocks","created_at":"2025-12-29T14:32:58.327421433+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-sny","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:32:59.27491603+01:00","created_by":"gdiazlo","metadata":"{}"}]} 167 + {"id":"hcs-tn3","title":"Run WebSocket benchmarks and collect results","description":"Execute the benchmark suite, collect memory and connection data, document findings.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T10:00:04.76879529+01:00","updated_at":"2025-12-30T10:22:46.346637622+01:00","closed_at":"2025-12-30T10:22:46.346637622+01:00","dependencies":[{"issue_id":"hcs-tn3","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:50.758778716+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-tn3","depends_on_id":"hcs-wkv","type":"blocks","created_at":"2025-12-30T10:01:15.964007648+01:00","created_by":"gdiazlo","metadata":"{}"}]} 168 + {"id":"hcs-ty6r","title":"Implement: Pipeline module","description":"Create lib/pipeline.ml:\n\n```ocaml\ntype t\nval create : Plug.t list -\u003e t\nval empty : t\nval plug : t -\u003e Plug.t -\u003e t\nval compose : t -\u003e t -\u003e t (* combine pipelines *)\nval apply : t -\u003e Server.handler -\u003e Server.handler\n```\n\nA pipeline is a reusable collection of plugs that can be applied to route groups.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:11:52.483211943+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:30:50.676175132+01:00","closed_at":"2026-01-03T21:30:50.676175132+01:00","close_reason":"Implemented Pipeline module","dependencies":[{"issue_id":"hcs-ty6r","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:12:44.447298938+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-ty6r","depends_on_id":"hcs-uoki","type":"blocks","created_at":"2026-01-03T21:13:29.94789855+01:00","created_by":"gdiazlo"}]} 169 + {"id":"hcs-tzc","title":"Implement Server.config type","description":"Implement server configuration in hcs-core/server_config.ml:\n\n```ocaml\ntype config = {\n host : string; (* default: \"0.0.0.0\" *)\n port : int; (* default: 8080 *)\n backlog : int; (* default: 2048 *)\n max_connections : int; (* default: 10000 *)\n\n (* Timeouts *)\n read_timeout : float; (* default: 60.0 *)\n write_timeout : float; (* default: 60.0 *)\n idle_timeout : float; (* default: 120.0 *)\n request_timeout : float; (* default: 30.0 *)\n\n (* Limits *)\n max_header_size : int; (* default: 8192 *)\n max_body_size : int64 option; (* None = unlimited *)\n\n (* Protocol *)\n http2 : bool; (* default: true *)\n buffer_size : int; (* default: 16384 *)\n\n (* TLS *)\n tls : Tls_config.server option;\n\n (* Compression *)\n compress_response : bool; (* default: true *)\n compression_min_size : int; (* default: 1024 *)\n compression_level : int; (* default: 6 *)\n\n (* Logging *)\n logger : Log.logger;\n}\n\nval default : config\n```\n\nPure configuration, no IO.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:33:15.561446445+01:00","updated_at":"2025-12-29T15:40:25.769211668+01:00","closed_at":"2025-12-29T15:40:25.769211668+01:00","dependencies":[{"issue_id":"hcs-tzc","depends_on_id":"hcs-rw6","type":"parent-child","created_at":"2025-12-29T14:33:40.219574299+01:00","created_by":"gdiazlo","metadata":"{}"}]} 170 + {"id":"hcs-ucw","title":"Implement Response helper module","description":"Implement response helpers in hcs-core/response.ml:\n\n```ocaml\nval make : ?version:version -\u003e ?headers:Headers.t -\u003e ?body:body -\u003e status -\u003e response\n\n(* Status shortcuts *)\nval ok : ?headers:Headers.t -\u003e body -\u003e response\nval created : ?headers:Headers.t -\u003e ?location:string -\u003e body -\u003e response\nval no_content : unit -\u003e response\nval bad_request : ?body:body -\u003e unit -\u003e response\nval unauthorized : ?www_authenticate:string -\u003e unit -\u003e response\nval forbidden : ?body:body -\u003e unit -\u003e response\nval not_found : ?body:body -\u003e unit -\u003e response\nval method_not_allowed : allowed:method_ list -\u003e unit -\u003e response\nval internal_error : ?body:body -\u003e unit -\u003e response\n(* ... all status helpers from spec ... *)\n\n(* Body helpers *)\nval text : string -\u003e response\nval html : string -\u003e response\nval redirect : ?permanent:bool -\u003e string -\u003e response\n\n(* Modify response *)\nval with_header : string -\u003e string -\u003e response -\u003e response\nval with_headers : (string * string) list -\u003e response -\u003e response\nval with_body : body -\u003e response -\u003e response\n```\n\nPure OCaml.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:34:17.870074295+01:00","updated_at":"2025-12-29T15:40:30.579234447+01:00","closed_at":"2025-12-29T15:40:30.579234447+01:00","dependencies":[{"issue_id":"hcs-ucw","depends_on_id":"hcs-dle","type":"parent-child","created_at":"2025-12-29T14:34:48.628725792+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-ucw","depends_on_id":"hcs-lpr","type":"blocks","created_at":"2025-12-29T14:34:55.629240942+01:00","created_by":"gdiazlo","metadata":"{}"}]} 171 + {"id":"hcs-uff","title":"docs: Authentication recipe","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:49.139387141+01:00","updated_at":"2026-01-03T01:09:58.312006912+01:00","closed_at":"2026-01-03T01:09:58.312006912+01:00"} 172 + {"id":"hcs-ugs","title":"Core Types and Foundations","description":"Implement core type foundations: method_, version, status, Headers module, body type, request/response records, and error types.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:19.301411166+01:00","updated_at":"2025-12-29T15:42:11.485073934+01:00","closed_at":"2025-12-29T15:42:11.485073934+01:00","dependencies":[{"issue_id":"hcs-ugs","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:25:54.989012647+01:00","created_by":"gdiazlo","metadata":"{}"}]} 173 + {"id":"hcs-ugz","title":"SSE first ping not sent promptly on H1 server","description":"On HTTP/1.1 server, SSE response does not flush initial event/ping promptly after headers. First message sometimes only arrives after buffering/timeout, causing clients to think connection is stalled. Suspected causes: missing early flush, chunked encoding/streaming not triggered, or output buffering in H1 writer.","acceptance_criteria":"- Repro: opening SSE endpoint over HTTP/1.1 delivers first event/ping within 250ms of connection establishment (on localhost).\n- No regressions for HTTP/2 SSE behavior.\n- Add or update an automated test that fails without the fix and passes with it (e.g., assert early data arrives).","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-02T15:17:28.140206861+01:00","updated_at":"2026-01-03T11:15:50.976265031+01:00","closed_at":"2026-01-03T11:15:50.976265031+01:00"} 174 + {"id":"hcs-uoki","title":"Design: Three-layer plug architecture","description":"Design the new plug architecture with three layers:\n\n**Layer 1 - Endpoint (global):**\n- Runs for ALL requests before routing\n- Static files, request_id, body parsing, session\n- Remove server config (port, bind, tls) - that belongs to Server\n\n**Layer 2 - Router Pipelines:**\n- Named pipelines: `browser`, `api`, etc.\n- Applied to route scopes via `pipe_through`\n- Example: CSRF for browser, rate-limit for api\n\n**Layer 3 - Per-route plugs:**\n- Individual routes can have additional plugs\n- Example: auth required only on specific routes\n\nDeliverable: Type signatures and API design document","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:11:49.593947839+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:30:45.623323802+01:00","closed_at":"2026-01-03T21:30:45.623323802+01:00","close_reason":"Completed design","dependencies":[{"issue_id":"hcs-uoki","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:12:39.387330447+01:00","created_by":"gdiazlo"}]} 175 + {"id":"hcs-urmr","title":"Remove Date_cache duplicate from h1_server.ml","status":"closed","priority":1,"issue_type":"chore","created_at":"2026-01-03T14:29:31.705466726+01:00","updated_at":"2026-01-03T14:31:02.528238279+01:00","closed_at":"2026-01-03T14:31:02.528238279+01:00"} 127 176 {"id":"hcs-uzm","title":"Middleware redesign: add circuit breaker and retry middlewares","description":"Expose Control.ml patterns (circuit breaker, retry) as proper Eio middlewares in middleware_eio.ml. Keep both rate limiters as they serve different purposes (token bucket for clients, sliding window for servers).","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-01-01T18:14:50.873049196+01:00","updated_at":"2026-01-01T18:17:42.278585485+01:00","closed_at":"2026-01-01T18:17:42.278585485+01:00"} 128 - {"id":"hcs-w0w","title":"LAS: Authentication module (auth.ml)","description":"Password hashing, current_user helper using Session, require_auth middleware, login/logout functions.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:37.261591945+01:00","updated_at":"2026-01-02T00:15:18.196756733+01:00","closed_at":"2026-01-02T00:15:18.196756733+01:00","dependencies":[{"issue_id":"hcs-w0w","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:33.336368591+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-w0w","depends_on_id":"hcs-gii","type":"blocks","created_at":"2026-01-01T23:43:13.641056385+01:00","created_by":"gdiazlo"}]} 129 - {"id":"hcs-w1c","title":"Create HCS WebSocket benchmark server","description":"OCaml server using lib/websocket.ml. Accept connections, keep alive with ping/pong, report connection count. Port configurable via CLI.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T09:59:57.95619465+01:00","updated_at":"2025-12-30T10:03:58.03114584+01:00","closed_at":"2025-12-30T10:03:58.03114584+01:00","dependencies":[{"issue_id":"hcs-w1c","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:25.560665813+01:00","created_by":"gdiazlo"}]} 130 - {"id":"hcs-wdm","title":"Verify tests pass after middleware changes","description":"","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:15:17.049685065+01:00","updated_at":"2026-01-01T18:17:42.271637225+01:00","closed_at":"2026-01-01T18:17:42.271637225+01:00","dependencies":[{"issue_id":"hcs-wdm","depends_on_id":"hcs-h2u","type":"blocks","created_at":"2026-01-01T18:15:31.619079845+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-wdm","depends_on_id":"hcs-d9v","type":"blocks","created_at":"2026-01-01T18:15:36.663284028+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-wdm","depends_on_id":"hcs-sby","type":"blocks","created_at":"2026-01-01T18:15:41.701006323+01:00","created_by":"gdiazlo"}]} 131 - {"id":"hcs-wkv","title":"Create WebSocket benchmark runner script","description":"Script like run_h2_comparison.sh. Start servers, run tests at 1k/10k/50k/100k connections, measure memory via /proc/[pid]/status VmRSS, report results.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T10:00:03.612055281+01:00","updated_at":"2025-12-30T10:14:42.952379356+01:00","closed_at":"2025-12-30T10:14:42.952379356+01:00","dependencies":[{"issue_id":"hcs-wkv","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:45.722495633+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-w1c","type":"blocks","created_at":"2025-12-30T10:00:55.80122372+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-1h7","type":"blocks","created_at":"2025-12-30T10:01:00.843226486+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-6ki","type":"blocks","created_at":"2025-12-30T10:01:05.885715216+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-6hx","type":"blocks","created_at":"2025-12-30T10:01:10.922318474+01:00","created_by":"gdiazlo"}]} 132 - {"id":"hcs-x1l","title":"Create benchmark runner script for standardized testing","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T22:21:46.718118939+01:00","updated_at":"2025-12-30T22:33:10.362379965+01:00","closed_at":"2025-12-30T22:33:10.362379965+01:00"} 133 - {"id":"hcs-y5a","title":"LAS: Data models (models.ml)","description":"Define types for user, link, vote, comment. Include JSON serialization helpers.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:27.179866273+01:00","updated_at":"2026-01-01T23:50:41.86681997+01:00","closed_at":"2026-01-01T23:50:41.86681997+01:00","dependencies":[{"issue_id":"hcs-y5a","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:23.256823169+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-y5a","depends_on_id":"hcs-dpu","type":"blocks","created_at":"2026-01-01T23:43:03.557959162+01:00","created_by":"gdiazlo"}]} 134 - {"id":"hcs-y9w","title":"TLS Configuration","description":"Implement Tls_config module for client and server TLS configuration with verification modes and system certificate loading.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:24.911800471+01:00","updated_at":"2025-12-29T15:25:06.384359847+01:00","closed_at":"2025-12-29T15:25:06.384359847+01:00","dependencies":[{"issue_id":"hcs-y9w","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:05.906211432+01:00","created_by":"gdiazlo"}]} 135 - {"id":"hcs-yg6","title":"LAS: Request handlers (handlers.ml)","description":"Handlers for index, show_link, create_link, vote, login, logout, register. Use Plug.Negotiate.respond for dual JSON/HTML.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:52.385545141+01:00","updated_at":"2026-01-02T10:23:27.072133297+01:00","closed_at":"2026-01-02T10:23:27.072133297+01:00","dependencies":[{"issue_id":"hcs-yg6","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:48.451290008+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-yg6","depends_on_id":"hcs-gii","type":"blocks","created_at":"2026-01-01T23:43:23.721075403+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-yg6","depends_on_id":"hcs-w0w","type":"blocks","created_at":"2026-01-01T23:43:28.763639466+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-yg6","depends_on_id":"hcs-pod","type":"blocks","created_at":"2026-01-01T23:43:33.804311531+01:00","created_by":"gdiazlo"}]} 177 + {"id":"hcs-v4al","title":"Implement: Router scopes with pipe_through","description":"Extend Router to support scoped routes with pipelines:\n\n```ocaml\nRouter.scope \"/api\" ~through:api_pipeline [\n Route.get \"/posts\" list_posts;\n Route.post \"/posts\" create_post;\n]\n\nRouter.scope \"/\" ~through:browser_pipeline [\n Route.get \"/\" home;\n Route.get \"/login\" login_form;\n]\n```\n\nWhen a route matches, its scope's pipeline runs before the handler.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:11:56.252334871+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:30:55.732720684+01:00","closed_at":"2026-01-03T21:30:55.732720684+01:00","close_reason":"Implemented router scopes","dependencies":[{"issue_id":"hcs-v4al","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:12:49.502773792+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-v4al","depends_on_id":"hcs-uoki","type":"blocks","created_at":"2026-01-03T21:13:35.004673762+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-v4al","depends_on_id":"hcs-ty6r","type":"blocks","created_at":"2026-01-03T21:13:50.176121606+01:00","created_by":"gdiazlo"}]} 178 + {"id":"hcs-vjo","title":"docs: Installation guide","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T00:44:18.366102527+01:00","updated_at":"2026-01-03T00:48:23.81083899+01:00","closed_at":"2026-01-03T00:48:23.81083899+01:00","dependencies":[{"issue_id":"hcs-vjo","depends_on_id":"hcs-0bi","type":"blocks","created_at":"2026-01-03T00:45:24.304083004+01:00","created_by":"gdiazlo","metadata":"{}"}]} 179 + {"id":"hcs-vwmd","title":"docs: PubSub guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:44:56.162777901+01:00","updated_at":"2026-01-03T01:03:33.230785198+01:00","closed_at":"2026-01-03T01:03:33.230785198+01:00"} 180 + {"id":"hcs-w0w","title":"LAS: Authentication module (auth.ml)","description":"Password hashing, current_user helper using Session, require_auth middleware, login/logout functions.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:37.261591945+01:00","updated_at":"2026-01-02T00:15:18.196756733+01:00","closed_at":"2026-01-02T00:15:18.196756733+01:00","dependencies":[{"issue_id":"hcs-w0w","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:33.336368591+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-w0w","depends_on_id":"hcs-gii","type":"blocks","created_at":"2026-01-01T23:43:13.641056385+01:00","created_by":"gdiazlo","metadata":"{}"}]} 181 + {"id":"hcs-w1c","title":"Create HCS WebSocket benchmark server","description":"OCaml server using lib/websocket.ml. Accept connections, keep alive with ping/pong, report connection count. Port configurable via CLI.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T09:59:57.95619465+01:00","updated_at":"2025-12-30T10:03:58.03114584+01:00","closed_at":"2025-12-30T10:03:58.03114584+01:00","dependencies":[{"issue_id":"hcs-w1c","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:25.560665813+01:00","created_by":"gdiazlo","metadata":"{}"}]} 182 + {"id":"hcs-wdm","title":"Verify tests pass after middleware changes","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T18:15:17.049685065+01:00","updated_at":"2026-01-01T18:17:42.271637225+01:00","closed_at":"2026-01-01T18:17:42.271637225+01:00","dependencies":[{"issue_id":"hcs-wdm","depends_on_id":"hcs-h2u","type":"blocks","created_at":"2026-01-01T18:15:31.619079845+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-wdm","depends_on_id":"hcs-d9v","type":"blocks","created_at":"2026-01-01T18:15:36.663284028+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-wdm","depends_on_id":"hcs-sby","type":"blocks","created_at":"2026-01-01T18:15:41.701006323+01:00","created_by":"gdiazlo","metadata":"{}"}]} 183 + {"id":"hcs-wkv","title":"Create WebSocket benchmark runner script","description":"Script like run_h2_comparison.sh. Start servers, run tests at 1k/10k/50k/100k connections, measure memory via /proc/[pid]/status VmRSS, report results.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T10:00:03.612055281+01:00","updated_at":"2025-12-30T10:14:42.952379356+01:00","closed_at":"2025-12-30T10:14:42.952379356+01:00","dependencies":[{"issue_id":"hcs-wkv","depends_on_id":"hcs-jk8","type":"parent-child","created_at":"2025-12-30T10:00:45.722495633+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-w1c","type":"blocks","created_at":"2025-12-30T10:00:55.80122372+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-1h7","type":"blocks","created_at":"2025-12-30T10:01:00.843226486+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-6ki","type":"blocks","created_at":"2025-12-30T10:01:05.885715216+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-wkv","depends_on_id":"hcs-6hx","type":"blocks","created_at":"2025-12-30T10:01:10.922318474+01:00","created_by":"gdiazlo","metadata":"{}"}]} 184 + {"id":"hcs-x1l","title":"Create benchmark runner script for standardized testing","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T22:21:46.718118939+01:00","updated_at":"2025-12-30T22:33:10.362379965+01:00","closed_at":"2025-12-30T22:33:10.362379965+01:00"} 185 + {"id":"hcs-xg9n","title":"Fix docs/plugs/reference.md - create or remove broken link","status":"closed","priority":2,"issue_type":"chore","created_at":"2026-01-03T14:29:32.650292605+01:00","updated_at":"2026-01-03T14:31:22.800247446+01:00","closed_at":"2026-01-03T14:31:22.800247446+01:00"} 186 + {"id":"hcs-xht","title":"HCS Documentation","description":"Comprehensive documentation for HCS library similar to Phoenix docs style. Concise, no claims, working code snippets, organized under docs/ folder.","status":"open","priority":2,"issue_type":"epic","created_at":"2026-01-03T00:43:27.786989188+01:00","updated_at":"2026-01-03T00:43:27.786989188+01:00"} 187 + {"id":"hcs-xw7","title":"SSE: respond_*_stream should not swallow all exceptions","description":"In lib/sse.ml respond_with_stream/respond_raw_stream treat any exception from Eio.Stream.take as end-of-stream (with _ -\u003e None). This can cause SSE connections to terminate immediately and hides real errors (cancellation, logic bugs). Narrow exception handling to End_of_file or propagate/log unexpected exceptions.","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-02T14:05:48.68753041+01:00","updated_at":"2026-01-02T14:06:23.99837942+01:00","closed_at":"2026-01-02T14:06:23.99837942+01:00"} 188 + {"id":"hcs-y4ra","title":"Test: Verify all tests pass after refactor","description":"Run full test suite:\n- dune build\n- dune test\n- Manual test of las application\n- Verify hs (file server) still works (doesn't use Endpoint)","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T20:59:48.153343384+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:11:28.352189828+01:00","closed_at":"2026-01-03T21:11:28.352189828+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-y4ra","depends_on_id":"hcs-j7fj","type":"blocks","created_at":"2026-01-03T21:00:38.071975277+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-y4ra","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:39.745458479+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-y4ra","depends_on_id":"hcs-lskj","type":"blocks","created_at":"2026-01-03T21:00:43.127315881+01:00","created_by":"gdiazlo"}]} 189 + {"id":"hcs-y5a","title":"LAS: Data models (models.ml)","description":"Define types for user, link, vote, comment. Include JSON serialization helpers.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:27.179866273+01:00","updated_at":"2026-01-01T23:50:41.86681997+01:00","closed_at":"2026-01-01T23:50:41.86681997+01:00","dependencies":[{"issue_id":"hcs-y5a","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:23.256823169+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-y5a","depends_on_id":"hcs-dpu","type":"blocks","created_at":"2026-01-01T23:43:03.557959162+01:00","created_by":"gdiazlo","metadata":"{}"}]} 190 + {"id":"hcs-y9w","title":"TLS Configuration","description":"Implement Tls_config module for client and server TLS configuration with verification modes and system certificate loading.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-29T14:25:24.911800471+01:00","updated_at":"2025-12-29T15:25:06.384359847+01:00","closed_at":"2025-12-29T15:25:06.384359847+01:00","dependencies":[{"issue_id":"hcs-y9w","depends_on_id":"hcs-zba","type":"parent-child","created_at":"2025-12-29T14:26:05.906211432+01:00","created_by":"gdiazlo","metadata":"{}"}]} 191 + {"id":"hcs-yg6","title":"LAS: Request handlers (handlers.ml)","description":"Handlers for index, show_link, create_link, vote, login, logout, register. Use Plug.Negotiate.respond for dual JSON/HTML.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-01T23:41:52.385545141+01:00","updated_at":"2026-01-02T10:23:27.072133297+01:00","closed_at":"2026-01-02T10:23:27.072133297+01:00","dependencies":[{"issue_id":"hcs-yg6","depends_on_id":"hcs-62k","type":"parent-child","created_at":"2026-01-01T23:42:48.451290008+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-yg6","depends_on_id":"hcs-gii","type":"blocks","created_at":"2026-01-01T23:43:23.721075403+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-yg6","depends_on_id":"hcs-w0w","type":"blocks","created_at":"2026-01-01T23:43:28.763639466+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-yg6","depends_on_id":"hcs-pod","type":"blocks","created_at":"2026-01-01T23:43:33.804311531+01:00","created_by":"gdiazlo","metadata":"{}"}]} 192 + {"id":"hcs-yhar","title":"Release: Bump version to 0.2.0","description":"Final release tasks:\n\n1. Update dune-project version 0.1.1 → 0.2.0\n2. Regenerate hcs.opam\n3. Final review of CHANGELOG\n4. Create git tag v0.2.0\n5. Push to remote","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:12:18.944912994+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:31:26.067799605+01:00","closed_at":"2026-01-03T21:31:26.067799605+01:00","close_reason":"Version bumped to 0.2.0","dependencies":[{"issue_id":"hcs-yhar","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:13:24.89058491+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-yhar","depends_on_id":"hcs-lsmn","type":"blocks","created_at":"2026-01-03T21:15:31.093477697+01:00","created_by":"gdiazlo"}]} 193 + {"id":"hcs-yppn","title":"Design: Define App module interface","description":"Design the new App module interface:\n- App.config: secret_key_base, health_check (app-level only)\n- App.t: config, plugs, router, ws_handler\n- App.create: takes App.config\n- App.start: takes App.t, Server.config, and env\n- Remove all server-level config (port, bind, domains, protocol, tls) from App\n\nDeliverable: Type signatures and interface documentation","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T20:59:33.999218536+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:10:58.025296424+01:00","closed_at":"2026-01-03T21:10:58.025296424+01:00","close_reason":"Superseded by expanded scope - adding router pipelines","dependencies":[{"issue_id":"hcs-yppn","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:00:09.419619431+01:00","created_by":"gdiazlo"}]} 194 + {"id":"hcs-z64a","title":"Implement: Per-route plugs on Route","description":"Allow individual routes to have plugs:\n\n```ocaml\nRoute.get \"/admin/users\" admin_users\n |\u003e Route.plug (Plug.Auth.require ~role:`Admin ())\n |\u003e Route.plug (Plug.Audit.log ())\n```\n\nRoute plugs run AFTER scope pipeline, BEFORE handler.\n\nFlow: Endpoint plugs → Scope pipeline → Route plugs → Handler","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-03T21:11:59.845880917+01:00","created_by":"gdiazlo","updated_at":"2026-01-03T21:31:00.788849709+01:00","closed_at":"2026-01-03T21:31:00.788849709+01:00","close_reason":"Implemented per-route plugs","dependencies":[{"issue_id":"hcs-z64a","depends_on_id":"hcs-1lvl","type":"parent-child","created_at":"2026-01-03T21:12:54.557265984+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-z64a","depends_on_id":"hcs-uoki","type":"blocks","created_at":"2026-01-03T21:13:40.060602624+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-z64a","depends_on_id":"hcs-v4al","type":"blocks","created_at":"2026-01-03T21:13:55.223987403+01:00","created_by":"gdiazlo"}]} 136 195 {"id":"hcs-zba","title":"HCS HTTP Library Implementation","description":"Implement the hcs HTTP library for OCaml 5+ supporting HTTP/1.1, HTTP/2, and WebSockets. Built with a runtime-agnostic core to support Eio initially with Lwt support planned for the future. Features zero-copy streaming and minimal allocations.\n\nDesign Principle: The library should have a pure functional core with IO effects abstracted behind a runtime interface, allowing future Lwt integration without major rewrites.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-29T14:25:07.01892354+01:00","updated_at":"2025-12-29T17:57:35.070502613+01:00","closed_at":"2025-12-29T17:57:35.070502613+01:00"} 137 - {"id":"hcs-zft","title":"Document CODEC implementation examples","description":"Document how users can implement their own CODEC for various formats. Include examples in documentation/comments showing the pattern:\n\n```ocaml\n(* Example: User implements JSON codec with their preferred library *)\nmodule My_json_codec : Hcs.CODEC = struct\n type 'a encoder = 'a -\u003e Yojson.Safe.t (* or Jsonm, Jsoo, etc. *)\n type 'a decoder = Yojson.Safe.t -\u003e ('a, string) result\n \n let content_type = \"application/json\"\n \n let encode enc value =\n try Ok (Cstruct.of_string (Yojson.Safe.to_string (enc value)))\n with exn -\u003e Error (Printexc.to_string exn)\n \n let decode dec buf =\n try \n let json = Yojson.Safe.from_string (Cstruct.to_string buf) in\n dec json\n with exn -\u003e Error (Printexc.to_string exn)\n \n let encode_stream _ _ = None (* Optional streaming *)\n let decode_stream _ _ = None\nend\n\n(* Example: MessagePack codec *)\nmodule My_msgpack_codec : Hcs.CODEC = struct\n (* Similar pattern with msgpck library *)\nend\n```\n\nThis is documentation only - no actual JSON library dependency in hcs. Users choose their own serialization libraries.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-29T14:28:49.108715641+01:00","updated_at":"2025-12-29T17:32:45.942298931+01:00","closed_at":"2025-12-29T17:32:45.942298931+01:00","labels":["codec","optional"],"dependencies":[{"issue_id":"hcs-zft","depends_on_id":"hcs-m4r","type":"parent-child","created_at":"2025-12-29T14:29:01.540146453+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-zft","depends_on_id":"hcs-pwc","type":"blocks","created_at":"2025-12-29T14:29:03.003001157+01:00","created_by":"gdiazlo"}]} 138 - {"id":"hcs-zln","title":"Update benchmark server with --domains flag","description":"Add --domains N flag to bench_server_h2.exe to test with configurable domain count.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:56.907974106+01:00","updated_at":"2025-12-30T09:16:33.434469675+01:00","closed_at":"2025-12-30T09:16:33.434469675+01:00","dependencies":[{"issue_id":"hcs-zln","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:24.184829345+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-zln","depends_on_id":"hcs-k8f","type":"blocks","created_at":"2025-12-30T09:06:39.306344162+01:00","created_by":"gdiazlo"}]} 196 + {"id":"hcs-zft","title":"Document CODEC implementation examples","description":"Document how users can implement their own CODEC for various formats. Include examples in documentation/comments showing the pattern:\n\n```ocaml\n(* Example: User implements JSON codec with their preferred library *)\nmodule My_json_codec : Hcs.CODEC = struct\n type 'a encoder = 'a -\u003e Yojson.Safe.t (* or Jsonm, Jsoo, etc. *)\n type 'a decoder = Yojson.Safe.t -\u003e ('a, string) result\n \n let content_type = \"application/json\"\n \n let encode enc value =\n try Ok (Cstruct.of_string (Yojson.Safe.to_string (enc value)))\n with exn -\u003e Error (Printexc.to_string exn)\n \n let decode dec buf =\n try \n let json = Yojson.Safe.from_string (Cstruct.to_string buf) in\n dec json\n with exn -\u003e Error (Printexc.to_string exn)\n \n let encode_stream _ _ = None (* Optional streaming *)\n let decode_stream _ _ = None\nend\n\n(* Example: MessagePack codec *)\nmodule My_msgpack_codec : Hcs.CODEC = struct\n (* Similar pattern with msgpck library *)\nend\n```\n\nThis is documentation only - no actual JSON library dependency in hcs. Users choose their own serialization libraries.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-29T14:28:49.108715641+01:00","updated_at":"2025-12-29T17:32:45.942298931+01:00","closed_at":"2025-12-29T17:32:45.942298931+01:00","labels":["codec","optional"],"dependencies":[{"issue_id":"hcs-zft","depends_on_id":"hcs-m4r","type":"parent-child","created_at":"2025-12-29T14:29:01.540146453+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-zft","depends_on_id":"hcs-pwc","type":"blocks","created_at":"2025-12-29T14:29:03.003001157+01:00","created_by":"gdiazlo","metadata":"{}"}]} 197 + {"id":"hcs-zln","title":"Update benchmark server with --domains flag","description":"Add --domains N flag to bench_server_h2.exe to test with configurable domain count.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T09:05:56.907974106+01:00","updated_at":"2025-12-30T09:16:33.434469675+01:00","closed_at":"2025-12-30T09:16:33.434469675+01:00","dependencies":[{"issue_id":"hcs-zln","depends_on_id":"hcs-zq3","type":"parent-child","created_at":"2025-12-30T09:06:24.184829345+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-zln","depends_on_id":"hcs-k8f","type":"blocks","created_at":"2025-12-30T09:06:39.306344162+01:00","created_by":"gdiazlo","metadata":"{}"}]} 198 + {"id":"hcs-zpwo","title":"docs: Channels guide","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T00:45:01.203966988+01:00","updated_at":"2026-01-03T01:20:01.382300868+01:00","closed_at":"2026-01-03T01:20:01.382300868+01:00"} 139 199 {"id":"hcs-zq3","title":"Multi-CPU Support for HTTP/2 Server","description":"Add configurable multi-CPU support using Eio domain pools. Allow users to specify max CPU count.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-30T09:04:59.162003477+01:00","updated_at":"2025-12-30T09:16:54.412371508+01:00","closed_at":"2025-12-30T09:16:54.412371508+01:00"} 140 - {"id":"hcs-zum","title":"Make zero-copy responses the default in high-level Server API","description":"","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-12-30T00:14:13.733230476+01:00","updated_at":"2025-12-30T00:21:07.346540362+01:00","closed_at":"2025-12-30T00:21:07.346540362+01:00"} 141 - {"id":"hcs-zya","title":"Implement Control module","description":"Implement control flow combinators. Split into core (pure) and runtime-specific parts:\n\nhcs-core/control.ml (pure combinators):\n```ocaml\n(* Retry logic - pure, takes a \"sleep\" function *)\nval with_retry :\n sleep:(float -\u003e unit) -\u003e\n max_attempts:int -\u003e\n backoff:(int -\u003e float) -\u003e\n should_retry:(error -\u003e bool) -\u003e\n (unit -\u003e ('a, error) result) -\u003e\n ('a, error) result\n\n(* Circuit breaker state machine - pure *)\ntype circuit_state = Closed | Open of float | HalfOpen\ntype circuit_breaker\nval create_breaker : failure_threshold:int -\u003e reset_timeout:float -\u003e circuit_breaker\nval breaker_allow : circuit_breaker -\u003e now:float -\u003e bool\nval breaker_record_success : circuit_breaker -\u003e unit\nval breaker_record_failure : circuit_breaker -\u003e now:float -\u003e unit\n```\n\nRuntime-specific (hcs-eio/control.ml):\n```ocaml\nval with_timeout : Eio.Time.clock -\u003e float -\u003e (unit -\u003e ('a, error) result) -\u003e ('a, error) result\nval with_cancel : Cancel.t -\u003e (unit -\u003e ('a, error) result) -\u003e ('a, error) result\nval with_deadline : Eio.Time.clock -\u003e float -\u003e (unit -\u003e ('a, error) result) -\u003e ('a, error) result\n```","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:29:29.643574962+01:00","updated_at":"2025-12-29T15:18:05.295780311+01:00","closed_at":"2025-12-29T15:18:05.295780311+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-zya","depends_on_id":"hcs-pnc","type":"parent-child","created_at":"2025-12-29T14:30:10.213773459+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-zya","depends_on_id":"hcs-8br","type":"blocks","created_at":"2025-12-29T14:30:10.494720544+01:00","created_by":"gdiazlo"},{"issue_id":"hcs-zya","depends_on_id":"hcs-gmb","type":"blocks","created_at":"2025-12-29T14:30:10.704956596+01:00","created_by":"gdiazlo"}]} 200 + {"id":"hcs-zum","title":"Make zero-copy responses the default in high-level Server API","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-12-30T00:14:13.733230476+01:00","updated_at":"2025-12-30T00:21:07.346540362+01:00","closed_at":"2025-12-30T00:21:07.346540362+01:00"} 201 + {"id":"hcs-zya","title":"Implement Control module","description":"Implement control flow combinators. Split into core (pure) and runtime-specific parts:\n\nhcs-core/control.ml (pure combinators):\n```ocaml\n(* Retry logic - pure, takes a \"sleep\" function *)\nval with_retry :\n sleep:(float -\u003e unit) -\u003e\n max_attempts:int -\u003e\n backoff:(int -\u003e float) -\u003e\n should_retry:(error -\u003e bool) -\u003e\n (unit -\u003e ('a, error) result) -\u003e\n ('a, error) result\n\n(* Circuit breaker state machine - pure *)\ntype circuit_state = Closed | Open of float | HalfOpen\ntype circuit_breaker\nval create_breaker : failure_threshold:int -\u003e reset_timeout:float -\u003e circuit_breaker\nval breaker_allow : circuit_breaker -\u003e now:float -\u003e bool\nval breaker_record_success : circuit_breaker -\u003e unit\nval breaker_record_failure : circuit_breaker -\u003e now:float -\u003e unit\n```\n\nRuntime-specific (hcs-eio/control.ml):\n```ocaml\nval with_timeout : Eio.Time.clock -\u003e float -\u003e (unit -\u003e ('a, error) result) -\u003e ('a, error) result\nval with_cancel : Cancel.t -\u003e (unit -\u003e ('a, error) result) -\u003e ('a, error) result\nval with_deadline : Eio.Time.clock -\u003e float -\u003e (unit -\u003e ('a, error) result) -\u003e ('a, error) result\n```","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-29T14:29:29.643574962+01:00","updated_at":"2025-12-29T15:18:05.295780311+01:00","closed_at":"2025-12-29T15:18:05.295780311+01:00","labels":["core"],"dependencies":[{"issue_id":"hcs-zya","depends_on_id":"hcs-pnc","type":"parent-child","created_at":"2025-12-29T14:30:10.213773459+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-zya","depends_on_id":"hcs-8br","type":"blocks","created_at":"2025-12-29T14:30:10.494720544+01:00","created_by":"gdiazlo","metadata":"{}"},{"issue_id":"hcs-zya","depends_on_id":"hcs-gmb","type":"blocks","created_at":"2025-12-29T14:30:10.704956596+01:00","created_by":"gdiazlo","metadata":"{}"}]}