Wymcp. Plugs. Era
(Wymcp v0.6.1)
View Source
Legacy-only
Era classification exists only because a second era does. This module is removed wholesale at the legacy decommission.
Era classification: tags every
POST with the era whose lane serves it — conn.assigns[:wymcp_era],
:modern or :legacy — and rejects the two era-mix shapes with 400.
Runs after the wire checks, which Wymcp.Router's wire-check invariant
names (they are era-invariant, and the singleton-header check guarantees
at most one Mcp-Session-Id before this plug reads it), and before
Wymcp.Plugs.Session, which passes modern-classified requests through
untouched.
The classification table — the modern
protocol fields are modern-era
evidence; initialize and Mcp-Session-Id are legacy-era evidence:
| Signals on the request | Classification |
|---|---|
protocol field(s), no session header, not initialize | :modern |
initialize, no protocol fields | :legacy |
Mcp-Session-Id, no protocol fields | :legacy (session lookup as before) |
protocol fields + Mcp-Session-Id | reject 400 — era mix |
initialize + protocol fields | reject 400 — era mix |
| none of the above | :legacy (Wymcp.Plugs.Session's missing-header rejection names both eras' next actions) |
Either required protocol field's presence classifies modern;
Wymcp.Plugs.ProtocolFields downstream enforces that both are present
and well-typed. Era-mix fails closed rather than ignoring the legacy
artifact: the spec's ignore rule is written for modern-only servers,
where no legacy lane exists to mis-route into — at a dual-era server a
client sending both signals may believe in session state the modern lane
would silently ignore. A request carrying all three signals meets the
session-header rejection first (the table's row order is the check
order). Headers are never era evidence; only body fields and
Mcp-Session-Id presence are read here. That a modern request's headers
mirror its body is a separate rule, enforced downstream by
Wymcp.Plugs.HeaderBinding once the era is known.