Follow-up from the PR #114 review (reviewer flagged Effect / Extensions / RouteDecision as growing public API without #[non_exhaustive]). RouteDecision was handled in #114; Effect was intentionally skipped (internal IR; #[non_exhaustive] would break the exhaustive effect classifiers). This issue is the remaining piece: Extensions.
Why
Extensions (cpex-core extensions/container.rs) is the external-facing type plugins and Praxis consume, and it gains an optional slot every few features. Without #[non_exhaustive], each added field is a breaking change for downstream crates — and adding #[non_exhaustive] later is itself breaking, so the cheap moment is now, before more external consumers exist.
Why it's not a one-liner
#[non_exhaustive] forbids external struct-literal construction — including Extensions { .. ..Default::default() } — so it breaks ~75 construction sites across the workspace (mostly tests + apl-cpex). It needs a constructor/builder to land alongside it.
Proposed
- Add a builder (or
with_* chain) as the sanctioned construction path.
- Migrate the ~75 sites to it.
- Then mark
Extensions #[non_exhaustive].
Alternative to weigh: private fields + accessors instead of #[non_exhaustive] (stronger encapsulation, larger migration).
Not urgent — no external consumer is broken today; this is forward-compat hygiene.
Follow-up from the PR #114 review (reviewer flagged
Effect/Extensions/RouteDecisionas growing public API without#[non_exhaustive]).RouteDecisionwas handled in #114;Effectwas intentionally skipped (internal IR;#[non_exhaustive]would break the exhaustive effect classifiers). This issue is the remaining piece:Extensions.Why
Extensions(cpex-coreextensions/container.rs) is the external-facing type plugins and Praxis consume, and it gains an optional slot every few features. Without#[non_exhaustive], each added field is a breaking change for downstream crates — and adding#[non_exhaustive]later is itself breaking, so the cheap moment is now, before more external consumers exist.Why it's not a one-liner
#[non_exhaustive]forbids external struct-literal construction — includingExtensions { .. ..Default::default() }— so it breaks ~75 construction sites across the workspace (mostly tests + apl-cpex). It needs a constructor/builder to land alongside it.Proposed
with_*chain) as the sanctioned construction path.Extensions#[non_exhaustive].Alternative to weigh: private fields + accessors instead of
#[non_exhaustive](stronger encapsulation, larger migration).Not urgent — no external consumer is broken today; this is forward-compat hygiene.