Skip to content

Commit 102f073

Browse files
etrclaude
andcommitted
Merge TASK-049 (handler_exception + internal_error_handler alias) into feature/v2.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 parents 67dd238 + 8d705a9 commit 102f073

16 files changed

Lines changed: 971 additions & 23 deletions

specs/tasks/M5-routing-lifecycle/TASK-049.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
Convert the existing DR-009 §5.2 dispatch-exception path into a hookable chain. The `internal_error_handler` setter becomes the last-position alias hook so all existing behavior is preserved.
99

1010
**Action Items:**
11-
- [ ] Fire `handler_exception` from each catch arm in `webserver_impl::dispatch_resource_handler` (`webserver.cpp:2392` and `webserver.cpp:2400`). Context: `handler_exception_ctx { const http_request& req; std::exception_ptr eptr; std::string_view message; }`. `message` is `e.what()` for the `std::exception` arm and the literal `"unknown exception"` for the `catch (...)` arm.
12-
- [ ] Chain semantics: hooks run in registration order; the first to return `hook_action::respond_with(r)` wins and the response is stashed into `mr->response_`. If no hook short-circuits, fall through to `run_internal_error_handler_safely(mr, message)` — preserving today's hardcoded fallback (empty-body 500 if the user `internal_error_handler` itself throws).
13-
- [ ] **Alias: `internal_error_handler(fn)`.** Internally register a `handler_exception` hook at LAST position that builds the same response `internal_error_handler` builds today and returns `hook_action::respond_with(...)`. Re-registration replaces the existing alias hook rather than chaining — single-slot semantics preserved for the alias surface (a user can still add their own `handler_exception` hooks before it via `add_hook`).
14-
- [ ] A throwing `handler_exception` hook is caught and the chain continues to the next hook (rather than short-circuiting to the hardcoded fallback immediately) — this is the one phase where exception-in-exception-handler does NOT abort the chain, because the whole point of the chain is exception recovery.
15-
- [ ] Doxygen on `internal_error_handler` setter notes it is an alias for a last-position `handler_exception` hook and references DR-012.
11+
- [x] Fire `handler_exception` from each catch arm in `webserver_impl::dispatch_resource_handler` (`webserver.cpp:2392` and `webserver.cpp:2400`). Context: `handler_exception_ctx { const http_request& req; std::exception_ptr eptr; std::string_view message; }`. `message` is `e.what()` for the `std::exception` arm and the literal `"unknown exception"` for the `catch (...)` arm.
12+
- [x] Chain semantics: hooks run in registration order; the first to return `hook_action::respond_with(r)` wins and the response is stashed into `mr->response_`. If no hook short-circuits, fall through to `run_internal_error_handler_safely(mr, message)` — preserving today's hardcoded fallback (empty-body 500 if the user `internal_error_handler` itself throws).
13+
- [x] **Alias: `internal_error_handler(fn)`.** Internally register a `handler_exception` hook at LAST position that builds the same response `internal_error_handler` builds today and returns `hook_action::respond_with(...)`. Re-registration replaces the existing alias hook rather than chaining — single-slot semantics preserved for the alias surface (a user can still add their own `handler_exception` hooks before it via `add_hook`).
14+
- [x] A throwing `handler_exception` hook is caught and the chain continues to the next hook (rather than short-circuiting to the hardcoded fallback immediately) — this is the one phase where exception-in-exception-handler does NOT abort the chain, because the whole point of the chain is exception recovery.
15+
- [x] Doxygen on `internal_error_handler` setter notes it is an alias for a last-position `handler_exception` hook and references DR-012.
1616

1717
**Dependencies:**
1818
- Blocked by: TASK-045, TASK-031 (existing error contract)
@@ -29,4 +29,4 @@ Convert the existing DR-009 §5.2 dispatch-exception path into a hookable chain.
2929
**Related Requirements:** PRD-HOOK-REQ-002, PRD-HOOK-REQ-003, PRD-HOOK-REQ-005, PRD-HOOK-REQ-009
3030
**Related Decisions:** DR-009, DR-012, §4.10, §5.2
3131

32-
**Status:** Not Started
32+
**Status:** Done

specs/tasks/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Nominally: **13 sequential tasks**, each S–XL. Most other tasks parallelize of
131131
| TASK-046 | Fire `connection_opened` / `connection_closed` / `accept_decision` | M5 | Done | TASK-045 |
132132
| TASK-047 | Fire `request_received` and `body_chunk` (pre-handler short-circuit) | M5 | Done | TASK-045 |
133133
| TASK-048 | Fire `route_resolved` and `before_handler`; wire 404/405/auth aliases | M5 | Done | TASK-045, TASK-027, TASK-031 |
134-
| TASK-049 | Fire `handler_exception`; wire `internal_error_handler` alias | M5 | Not Started | TASK-045, TASK-031 |
134+
| TASK-049 | Fire `handler_exception`; wire `internal_error_handler` alias | M5 | Done | TASK-045, TASK-031 |
135135
| TASK-050 | Fire `after_handler` (post-handler short-circuit), `response_sent`, `request_completed`; wire `log_access` alias | M5 | Not Started | TASK-045 |
136136
| TASK-051 | Per-route hooks (`http_resource::add_hook`) | M5 | Not Started | TASK-045, TASK-048, TASK-049, TASK-050 |
137137
| TASK-052 | Hook bus documentation, examples, benchmark, stress-test extension (touches back into TASK-040/041/042/043) | M5 | Not Started | TASK-045, TASK-046, TASK-047, TASK-048, TASK-049, TASK-050, TASK-051 |

0 commit comments

Comments
 (0)