Admit swarm bounds without a transport feature

Merged
VA
2d ago
+88-13

Cause

#778 (cebe2675e) gated SwarmClient behind grpc on native and wasm on wasm32. The portable client-swarm-views test target has no required features. Its shared bounds oracle (harness-fuzz/support/swarm_limits.rs, also used by the fuzz target) still validated bounds through SwarmClient::new. Any native feature set without grpc therefore failed to compile the target with E0432 (SwarmClient unresolved). That includes the poll-sweep set on x86_64-pc-windows-gnu.

Class and fix

The class is a portable contract that is reachable only through a transport-gated type. The swarm bounds rule is pure, so it now lives on the ungated SwarmClientLimits::validate(&ClientViewLimits):

  • SwarmClient::new calls it; its duplicated inline check is deleted.
  • The shared oracle calls it, plus ClientViews::new, so the portable test and the fuzz target no longer name a transport type.

The rule now has one owner, and it compiles under every feature set, so the portable test can't reach it through a gated type again.

Regression test and negative control

  • every_out_of_range_swarm_bound_is_rejected_without_a_transport breaks each of the seven bound relations in turn and requires rejection. The valid baseline must pass.
  • The existing negative_control_omitting_a_swarm_bound_is_rejected still covers the schema.

Verification

  • bb1 Linux, combined validation build: client-swarm-views 26/26 passed in 0.08 s.
  • Windows: cargo check --locked -p acyclic-harness --lib --tests --features filesystem-local,native-execution,test-support,terminal,tui,mcp-http,model-checking --target x86_64-pc-windows-gnu on bb1. Before (main): E0432 in client-swarm-views. After: passes with no errors (6m35s, combined validation branch).

Guarantee

Class: J, target and feature capability closure: a portable contract was reachable only through a transport-gated type. Structural fix: the bounds rule has a single owner, SwarmClientLimits::validate. It is ungated, so it compiles under every feature set, and SwarmClient::new delegates to it, which leaves no second copy.
Proof: every_out_of_range_swarm_bound_is_rejected_without_a_transport breaks each of the seven relations in its own case. A violations counter, independent of validate, asserts that each case breaks exactly 1 relation and that the baseline breaks 0. Each case must make validate return Err. Negative controls: deleting any one relation from validate fails its case (by construction; not run as a mutant), and negative_control_omitting_a_swarm_bound_is_rejected covers the schema side. The fuzz target shares the same oracle (harness-fuzz/support/swarm_limits.rs).
Entry points: SwarmClient::new, ClientViews::new and the fuzz support oracle all reach the rule only through validate. The Windows GNU --lib --tests check without grpc compiles all of them.
Gaps: none.

🤖 Generated with Claude Code