1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! Request lifecycle zones — the documented ordering contract for the
//! Arcature engine pipeline (engine spec §7).
//!
//! The pipeline is assembled in zones, each with a clear responsibility.
//! The ordering is justified by semantics and tested (see the proxy and
//! pipeline integration tests).
//!
//! ```text
//! incoming request
//! │
//! ▼
//! ┌─────────────────────────────────────┐
//! │ PRE ROUTING │
//! │ request-id correlation │ RequestIdLayer (observe)
//! │ proxy policy │ ProxyLayer
//! └─────────────────┬───────────────────┘
//! │
//! ▼
//! ┌─────────────────────────────────────┐
//! │ ROUTING │
//! │ Axum route selection │ Router (via into_service)
//! └─────────────────┬───────────────────┘
//! │
//! ▼
//! ┌─────────────────────────────────────┐
//! │ POST ROUTING GLOBAL │
//! │ maintenance gate │ MaintenanceLayer (pages)
//! │ Inertia protocol │ InertiaLayer (inertia)
//! │ error mapping │ ErrorMappingLayer (dx)
//! │ matched-route enrichment │ MatchedRoute adapter (observe)
//! │ HTTP instrumentation │ HttpLayer (observe)
//! └─────────────────┬───────────────────┘
//! │
//! ▼
//! ┌─────────────────────────────────────┐
//! │ HANDLER / FALLBACK │
//! │ application logic │ handler
//! │ 404 fallback │ Pages::not_found_service (pages)
//! └─────────────────────────────────────┘
//! ```
//!
//! # Why this ordering
//!
//! - **Request-id outermost (pre-routing)**: every response — including proxy
//! redirects, maintenance 503s, and 404 fallbacks — receives an
//! `x-request-id` header (engine spec §8). RequestIdLayer wraps the entire
//! service, not just the router, so it runs before anything else.
//!
//! - **Proxy before routing**: the proxy function can rewrite the URI before
//! route selection, so a rewrite to a registered route actually hits that
//! route (engine spec §3/§4/§6). This is the fix for the architecture
//! mismatch where the proxy was previously wired via `Router::layer`
//! (post-routing).
//!
//! - **Maintenance outside Inertia**: a maintenance 503 short-circuits before
//! Inertia processes the response, so maintenance does not produce an
//! Inertia page — it produces a self-contained 503 HTML (engine spec §10).
//! The request-id is still set (pre-routing).
//!
//! - **Inertia outside observe route-layers**: Inertia intercepts the response
//! for protocol conversion; the observe layers record the *original* handler
//! response (status, route template) before Inertia converts it. This
//! matches the observe crate's documented ordering (RequestIdLayer →
//! MatchedRoute → HttpLayer → handler).
//!
//! - **Error mapping inside Inertia**: the error-mapping layer reformats
//! handler responses (e.g. 5xx → Problem Details) after the handler has
//! run but before Inertia processes the response on the response path.
//! Maintenance and Inertia short-circuits are already handled on the
//! request path, so error mapping does not interfere with them (A10).
//!
//! - **MatchedRoute adapter outside HttpLayer**: the adapter sets
//! `MatchedRoute` from axum's `MatchedPath` before `HttpLayer` reads it
//! (engine spec §8: observe records route templates, not concrete paths).
//! Both are `route_layer` — they run only on matched routes, not fallbacks.
//!
//! - **404 fallback via `fallback_service`**: the pages 404 handler is
//! installed as the router's fallback, so unmatched routes receive the
//! self-contained 404 HTML (engine spec §9/§37). The `layer`-applied
//! middleware (maintenance, Inertia) wraps the fallback too, so a
//! maintenance-mode 404 is a 503, not a 404.