Wymcp.Plugs.Era (Wymcp v0.1.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 (docs/glossary.md, 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 three wire checks (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 (docs/glossary.md, protocol fields) are modern-era evidence; initialize and Mcp-Session-Id are legacy-era evidence:

Signals on the requestClassification
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-Idreject 400 — era mix
initialize + protocol fieldsreject 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 (MCP-Protocol-Version binding is a planned design of its own); only body fields and Mcp-Session-Id presence are read here.