Skip to content

Commit 0e0d001

Browse files
etrclaude
andcommitted
TASK-006: housekeeping (mark task complete in index)
Update specs/tasks/_index.md to change TASK-006 status from 'In Progress' to 'Done', matching the completed state in TASK-006.md and the pattern used by TASK-003, TASK-004, and TASK-005. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c93ee31 commit 0e0d001

1 file changed

Lines changed: 188 additions & 0 deletions

File tree

specs/tasks/_index.md

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# libhttpserver v2.0 — Task Plan
2+
3+
**Status:** Draft 1
4+
**Last updated:** 2026-04-30
5+
**Owner:** Sebastiano Merlino
6+
**Inputs:** [specs/product_specs.md](../product_specs.md), [specs/architecture/](../architecture/)
7+
8+
---
9+
10+
## Overview
11+
12+
44 tasks across 6 milestones implementing the v2.0 clean-cutover release. The v2.0 cutover is single-shot (no Alpha→Beta→GA phasing per PRD §1), so milestones are technical layers that each leave the public API in a compilable state and exercise an outcome a downstream consumer would care about. There is no parallel maintenance branch — v1.x is end-of-life on the day v2.0 ships (DR-011, OQ-007).
13+
14+
## Milestones
15+
16+
| ID | Name | Outcome | Tasks |
17+
|---|---|---|---|
18+
| M1 | Foundation | C++20 floor, header layout & guards, primitive types (`http_method`, `method_set`), `feature_unavailable`, `iovec_entry`, `httpserver::constants`, header-hygiene CI gate. After M1 the library still functions as v1 — additive only. | TASK-001 .. TASK-007 |
19+
| M2 | Response Refactor | `http_response` is a value type with SBO body, factories, fluent `with_*` chains, const-correct getters. Public `*_response` subclasses gone. After M2 a downstream consumer can build & chain a response. | TASK-008 .. TASK-013 |
20+
| M3 | Webserver internal & Request Refactor | `webserver_impl` and `http_request_impl` PIMPL split; per-connection arena allocator; `const&` / `string_view` getters; high-level GnuTLS accessors. Public headers are free of `<microhttpd.h>`, `<pthread.h>`, `<gnutls/gnutls.h>`, `<sys/socket.h>`. | TASK-014 .. TASK-020 |
21+
| M4 | Handler & Resource Model | `http_resource` allow-mask via `method_set`, snake_case `render_*`, smart-pointer registration, `register_path`/`register_prefix`, lambda `on_*`, generic `route()`. After M4 a consumer can register handlers in either form. | TASK-021 .. TASK-026 |
22+
| M5 | Routing, Lifecycle, Builder & Features | 3-tier route table (hash + radix + regex) with LRU cache, v1-corpus regression gate, name canonicalization (`stop_and_wait`, `block_ip`/`unblock_ip`, `_handler` suffix), error-propagation contract, thread-safety stress test, builder cleanup, `features()`, websocket smart-pointer overloads, handler return-by-value dispatch cutover. After M5 the library is feature-complete. | TASK-027 .. TASK-036 |
23+
| M6 | Release Readiness | Build-flag-invariance CI test, sanitizer move tests, performance acceptance (`get_headers` ≥10×, `sizeof(http_resource)` shrink), examples (≤10 LOC hello world), README rewrite, RELEASE_NOTES.md, Doxygen refresh, SOVERSION bump 1→2, packaging. | TASK-037 .. TASK-044 |
24+
25+
## Dependency graph
26+
27+
```
28+
M1: Foundation
29+
└── 001 [C++20] ──→ 002 [headers/guards] ──┬──→ 003 [feature_unavailable]
30+
├──→ 004 [iovec_entry]
31+
├──→ 005 [http_method/method_set]
32+
├──→ 006 [constants]
33+
└──→ 007 [hygiene CI test]
34+
35+
M2: Response Refactor (can begin once 002 lands)
36+
└── 008 [detail::body] ──→ 009 [http_response value+SBO] ──┬──→ 010 [factories]
37+
├──→ 011 [const accessors]
38+
├──→ 012 [fluent setters]
39+
└──→ 013 [remove subclasses]
40+
41+
M3: Webserver internal & Request Refactor (can begin once 002 lands)
42+
└── 014 [webserver_impl skeleton] ──→ 015 [http_request_impl skeleton] ──→ 016 [arena]
43+
├──→ 017 [const& getters]
44+
├──→ 018 [string_view getters]
45+
└──→ 019 [GnuTLS accessors]
46+
└──→ 020 [final hygiene sweep]
47+
48+
M4: Handler & Resource Model (depends on M1 005 + M2 009 + M3 014)
49+
└── 021 [method_set on http_resource] ──→ 022 [snake_case render_*] ─┐
50+
023 [smart-ptr register_resource] ──→ 024 [register_path/prefix] ┤
51+
025 [on_*] ───┼──→ 026 [route()]
52+
53+
M5: Routing, Lifecycle, Builder & Features
54+
└── 027 [3-tier route table] ──→ 028 [v1 routing-corpus regression]
55+
029 [stop_and_wait + block_ip] (depends on 014)
56+
030 [_handler suffix + explicit] (depends on 014)
57+
031 [error propagation] (depends on 027, 030)
58+
032 [thread-safety stress test] (depends on 027, 031)
59+
033 [create_webserver cleanup] (depends on 006, 014)
60+
034 [features() + flag-independence] (depends on 003, 019, 033)
61+
035 [websocket smart-ptr] (depends on 014, 034)
62+
036 [handler return-by-value dispatch] (depends on 022, 025, 027, 031)
63+
64+
M6: Release Readiness
65+
└── 037 [build-flag invariance CI] (depends on 034)
66+
038 [sanitizer move tests] (depends on 009, 036)
67+
039 [performance acceptance] (depends on 017, 018, 021)
68+
040 [examples] (depends on 025, 036) ──→ 041 [README] ──→ 042 [RELEASE_NOTES] ──→ 043 [Doxygen] ──→ 044 [SOVERSION bump]
69+
```
70+
71+
## Critical path
72+
73+
The longest dependency chain (each link representing a true blocker, not just a milestone boundary):
74+
75+
```
76+
001 → 002 → 014 → 015 → 016 → 027 → 028 → 036 → 040 → 041 → 042 → 043 → 044
77+
(C++20 → headers → webserver_impl → request_impl → arena → route table → routing regression → return-by-value → examples → README → RELEASE_NOTES → Doxygen → SOVERSION)
78+
```
79+
80+
Nominally: **13 sequential tasks**, each S–XL. Most other tasks parallelize off this spine — M2 (response) is fully independent of M3 (request) once TASK-002 lands, M4 fans out from M1 + M2 + early M3, and M6's documentation and tests can start mid-M5 once their respective inputs are available.
81+
82+
## Task Status
83+
84+
| # | Task | Milestone | Status | Blocked by |
85+
|---|------|-----------|--------|------------|
86+
| TASK-001 | Bump C++ standard floor to C++20 | M1 | In Progress | None |
87+
| TASK-002 | Public/private header layout and inclusion guards | M1 | Done | TASK-001 |
88+
| TASK-003 | Add `httpserver::feature_unavailable` exception type | M1 | Done | TASK-002 |
89+
| TASK-004 | Library-defined `iovec_entry` POD with layout-pinning asserts | M1 | Done | TASK-002 |
90+
| TASK-005 | Add `http_method` enum and `method_set` bitmask | M1 | Done | TASK-002 |
91+
| TASK-006 | Replace `#define` constants with `httpserver::constants` | M1 | Done | TASK-002 |
92+
| TASK-007 | CI test for public-header hygiene | M1 | Not Started | TASK-002 |
93+
| TASK-008 | Internal `detail::body` hierarchy | M2 | Not Started | TASK-002 |
94+
| TASK-009 | `http_response` value type with SBO buffer | M2 | Not Started | TASK-008 |
95+
| TASK-010 | `http_response` factory functions | M2 | Not Started | TASK-008, TASK-009, TASK-004 |
96+
| TASK-011 | `http_response` const-correct accessors | M2 | Not Started | TASK-009 |
97+
| TASK-012 | `http_response` fluent `with_*` setters | M2 | Not Started | TASK-009 |
98+
| TASK-013 | Remove `*_response` subclasses and dispatch virtuals | M2 | Not Started | TASK-009, TASK-010, TASK-011, TASK-012 |
99+
| TASK-014 | `webserver_impl` skeleton (PIMPL prep) | M3 | Not Started | TASK-002 |
100+
| TASK-015 | `http_request_impl` skeleton (PIMPL split) | M3 | Not Started | TASK-002, TASK-014 |
101+
| TASK-016 | Per-connection arena for `http_request_impl` | M3 | Not Started | TASK-014, TASK-015 |
102+
| TASK-017 | `http_request` container getters return `const&` | M3 | Not Started | TASK-015 |
103+
| TASK-018 | `http_request` single-key getters return `string_view`, all const | M3 | Not Started | TASK-015, TASK-016 |
104+
| TASK-019 | High-level GnuTLS accessors replacing `gnutls_session_t` | M3 | Not Started | TASK-015 |
105+
| TASK-020 | Final public-header backend-include sweep | M3 | Not Started | TASK-014, TASK-015, TASK-019 |
106+
| TASK-021 | `http_resource` allow-mask via `method_set` | M4 | Not Started | TASK-005 |
107+
| TASK-022 | Snake_case `render_*` overrides on `http_resource` | M4 | Not Started | TASK-021 |
108+
| TASK-023 | Smart-pointer `register_resource` overloads | M4 | Not Started | TASK-014 |
109+
| TASK-024 | `register_path` and `register_prefix` (replace `bool family`) | M4 | Not Started | TASK-023 |
110+
| TASK-025 | Lambda handler entry points `on_*` | M4 | Not Started | TASK-005, TASK-009, TASK-014 |
111+
| TASK-026 | Generic `webserver::route(method, path, handler)` | M4 | Not Started | TASK-005, TASK-025 |
112+
| TASK-027 | 3-tier route table with LRU cache | M5 | Not Started | TASK-005, TASK-014, TASK-021, TASK-024, TASK-025, TASK-026 |
113+
| TASK-028 | Routing-semantics regression gate | M5 | Not Started | TASK-027 |
114+
| TASK-029 | Naming consistency — `stop_and_wait`, `block_ip`/`unblock_ip` | M5 | Not Started | TASK-014 |
115+
| TASK-030 | `_handler` suffix renames + `explicit` constructor | M5 | Not Started | TASK-014 |
116+
| TASK-031 | Handler error-propagation contract (DR-009) | M5 | Not Started | TASK-027, TASK-030 |
117+
| TASK-032 | Thread-safety contract stress test (DR-008) | M5 | Not Started | TASK-027, TASK-031 |
118+
| TASK-033 | `create_webserver` builder cleanup | M5 | Not Started | TASK-006, TASK-014 |
119+
| TASK-034 | Build-flag-independent public API + `webserver::features()` | M5 | Not Started | TASK-003, TASK-019, TASK-033 |
120+
| TASK-035 | Smart-pointer `register_ws_resource` overloads | M5 | Not Started | TASK-014, TASK-034 |
121+
| TASK-036 | Handler return-by-value dispatch cutover | M5 | Not Started | TASK-022, TASK-025, TASK-027, TASK-031 |
122+
| TASK-037 | CI test for build-flag invariance | M6 | Not Started | TASK-034 |
123+
| TASK-038 | Sanitizer-clean tests for `http_response` move semantics | M6 | Not Started | TASK-009, TASK-036 |
124+
| TASK-039 | Performance acceptance (`get_headers`, `sizeof(http_resource)`) | M6 | Not Started | TASK-017, TASK-018, TASK-021 |
125+
| TASK-040 | Rewrite `examples/` | M6 | Not Started | TASK-025, TASK-036 |
126+
| TASK-041 | Rewrite `README.md` | M6 | Not Started | TASK-031, TASK-032, TASK-040 |
127+
| TASK-042 | Write `RELEASE_NOTES.md` for v2.0 | M6 | Not Started | TASK-041 |
128+
| TASK-043 | Doxygen / inline doc refresh | M6 | Not Started | TASK-031, TASK-034, TASK-041 |
129+
| TASK-044 | SOVERSION bump and packaging | M6 | Not Started | TASK-042, TASK-043 |
130+
131+
## PRD requirement coverage
132+
133+
Each PRD EARS requirement maps to one or more tasks below.
134+
135+
| PRD ID | Tasks |
136+
|---|---|
137+
| PRD-HDR-REQ-001 (no `<microhttpd.h>`) | TASK-002, TASK-014, TASK-015, TASK-020, TASK-007 |
138+
| PRD-HDR-REQ-002 (no `<pthread.h>`/`<sys/socket.h>`) | TASK-002, TASK-014, TASK-020, TASK-007 |
139+
| PRD-HDR-REQ-003 (no `<gnutls/gnutls.h>`) | TASK-019, TASK-020, TASK-007 |
140+
| PRD-HDR-REQ-004 (PIMPL — exempts `http_response`) | TASK-014, TASK-015 (positive rule); TASK-009 (exemption clause: `http_response` stays non-PIMPL) |
141+
| PRD-HDR-REQ-005 (remove dispatch virtuals) | TASK-013 |
142+
| PRD-FLG-REQ-001 (no `#ifdef HAVE_*`) | TASK-034, TASK-037 |
143+
| PRD-FLG-REQ-002 (sentinel/throw) | TASK-019, TASK-031, TASK-034, TASK-035 |
144+
| PRD-FLG-REQ-003 (`features()`) | TASK-034 |
145+
| PRD-FLG-REQ-004 (error names feature + flag) | TASK-003, TASK-034 |
146+
| PRD-FLG-REQ-005 (`feature_unavailable` from `runtime_error`) | TASK-003 |
147+
| PRD-CFG-REQ-001 (`bool` setter form) | TASK-033 |
148+
| PRD-CFG-REQ-002 (`constexpr` constants) | TASK-006, TASK-033 (verifies `create_webserver.hpp` carries no `#define`) |
149+
| PRD-CFG-REQ-003 (validate + throw) | TASK-033 |
150+
| PRD-CFG-REQ-004 (no `no_*` setters) | TASK-033 |
151+
| PRD-HDL-REQ-001 (handler signature) | TASK-025, TASK-036 |
152+
| PRD-HDL-REQ-002 (`on_*` entry points) | TASK-025, TASK-027 |
153+
| PRD-HDL-REQ-003 (smart-ptr registration) | TASK-023, TASK-035 |
154+
| PRD-HDL-REQ-004 (`register_prefix` not `bool family`) | TASK-024 |
155+
| PRD-HDL-REQ-005 (no raw-pointer registration) | TASK-023, TASK-035 |
156+
| PRD-HDL-REQ-006 (`route(method, path, handler)`) | TASK-005, TASK-026 |
157+
| PRD-RSP-REQ-001 (factory by value) | TASK-009, TASK-010 |
158+
| PRD-RSP-REQ-002 (no mutating accessors) | TASK-011 |
159+
| PRD-RSP-REQ-003 (no insert-on-miss) | TASK-011 |
160+
| PRD-RSP-REQ-004 (fluent return) | TASK-012 |
161+
| PRD-RSP-REQ-005 (`unauthorized` factory) | TASK-010 |
162+
| PRD-RSP-REQ-006 (no `*_response` classes) | TASK-013 |
163+
| PRD-RSP-REQ-007 (handler returns by value) | TASK-009, TASK-036 |
164+
| PRD-REQ-REQ-001 (`const&` getters) | TASK-017, TASK-018; TASK-039 (numeric §3.6 acceptance: ≥10× `get_headers()` speedup) |
165+
| PRD-REQ-REQ-002 (`is_allowed` const) | TASK-021 |
166+
| PRD-REQ-REQ-003 (bitmask method state) | TASK-005, TASK-021; TASK-039 (numeric §3.6 acceptance: `sizeof(http_resource)` shrink) |
167+
| PRD-NAM-REQ-001 (snake_case) | TASK-022, TASK-029 |
168+
| PRD-NAM-REQ-002 (one canonical verb) | TASK-029 |
169+
| PRD-NAM-REQ-003 (`_handler` suffix) | TASK-030 |
170+
| PRD-NAM-REQ-004 (`explicit` ctor) | TASK-030 |
171+
| PRD-NAM-REQ-005 (`block_ip`/`unblock_ip` only) | TASK-029 |
172+
173+
## Decision-record coverage
174+
175+
| DR | Tasks |
176+
|---|---|
177+
| DR-001 (C++20 floor) | TASK-001 |
178+
| DR-002 (header layout) | TASK-002, TASK-014, TASK-015 |
179+
| DR-003a (no PIMPL `http_response`) | TASK-009 |
180+
| DR-003b (PIMPL `webserver`/`http_request`) | TASK-014, TASK-015, TASK-016 |
181+
| DR-004 (handler return by value) | TASK-025, TASK-036 |
182+
| DR-005 (SBO body) | TASK-008, TASK-009, TASK-038 |
183+
| DR-006 (`http_method`/`method_set`) | TASK-005, TASK-021 |
184+
| DR-007 (3-tier route table) | TASK-027, TASK-028 |
185+
| DR-008 (thread-safety contract) | Implements: TASK-027 (shared_mutex), TASK-032 (stress test). Documents: TASK-041, TASK-043 |
186+
| DR-009 (error-propagation contract) | Implements: TASK-031. Documents: TASK-041, TASK-043 |
187+
| DR-010 (deferred / WS lifecycle) | TASK-035, TASK-036 |
188+
| DR-011 (SOVERSION-only versioning) | TASK-044 |

0 commit comments

Comments
 (0)