package federated // reachability_gate_test.go is the WS8 CI REACHABILITY GATE. It mirrors the intent of the X-Org-ID build tag // backdoor removal gate (Makefile verify-backdoor): that gate proves a dangerous code path cannot reach a // release binary; this gate proves NO federated emission path is live when MM_FEDERATED_DP_ENABLED is unset or // false. Together they are the two negative tests that keep an unsafe path dead by construction, not by // reviewer vigilance. // // With the flag off, three independent emission paths must all be inert: // // 1. NewActiveAggregator REFUSES to build (returns ErrDisabled), so no active aggregator, and therefore no // Emit path, can even be assembled. This is the hard construction guard. // 2. SpendGate.Charge returns ErrDisabled and writes NOTHING (no ledger insert, no audit event), so the hard // spend gate never persists a release on a disabled deploy. // 3. The inference client Teach transmits NOTHING while TeachingEnabled is false, so no contents scrubbed // craft signal leaves the box. // // If any of these started emitting with the flag off, the federated loop would be live in tenant LIVE, which is // exactly the posture this gate forbids. The point: no federated emission path is reachable when the flag is // unset. import ( "context" "errors" "net/http" "net/http/httptest" "sync/atomic" "testing" "time" "github.com/missionworkforce/missionmatch/internal/platform/config" "github.com/missionworkforce/missionmatch/internal/platform/inference" "github.com/missionworkforce/missionmatch/internal/platform/scrub" ) // flagOffConfig is the default in tenant LIVE federated posture: the DP master switch is off. Epsilon and delta // are present (they are config, not constants) but they never matter while the switch is off. func flagOffConfig() config.Federated { return config.Federated{DPEnabled: false, DPEpsilon: 10, DPDelta: 1e-7} } // TestReachabilityGateFlagOffNoActiveAggregator proves the hard construction guard: with the flag off, // NewActiveAggregator refuses to build and returns ErrDisabled, so no Emit path can be assembled. func TestReachabilityGateFlagOffNoActiveAggregator(t *testing.T) { cfg := flagOffConfig() gate := NewSpendGate(cfg, &fakeLedger{}, nil) agg, err := NewActiveAggregator(cfg, gate) if !errors.Is(err, ErrDisabled) { t.Fatalf("flag off NewActiveAggregator must return ErrDisabled, got %v", err) } if agg != nil { t.Fatal("flag off NewActiveAggregator must return a nil aggregator, so no Emit path exists") } } // TestReachabilityGateFlagOffChargeRefusesAndWritesNothing proves the hard spend gate is inert with the flag // off: Charge returns ErrDisabled and persists NO ledger row and emits NO audit event, so no release is ever // recorded on a disabled deploy. func TestReachabilityGateFlagOffChargeRefusesAndWritesNothing(t *testing.T) { cfg := flagOffConfig() store := &fakeLedger{} au := &fakeAuditor{} gate := NewSpendGate(cfg, store, nil) gate.auditW = au // observe that no audit event is written either rel := Release{ModelVersion: "v1.4.0", ContributingTenantCount: 5, Gaussian: GaussianRelease{NoiseSigma: 2, ClipNorm: 1}} _, err := gate.Charge(context.Background(), rel) if !errors.Is(err, ErrDisabled) { t.Fatalf("flag off Charge must return ErrDisabled, got %v", err) } if len(store.rows) != 0 || len(store.insertSeen) != 0 { t.Fatalf("flag off Charge wrote to the ledger: rows=%d inserts=%d", len(store.rows), len(store.insertSeen)) } if len(au.events) != 0 { t.Fatalf("flag off Charge emitted an audit event: %d events", len(au.events)) } } // TestReachabilityGateFlagOffTeachTransmitsNothing proves the inference client transmits NO craft signal while // TeachingEnabled is false (the federated transmission flag, off in tenant LIVE). It points the client at a // counting server and asserts a clean, boundary valid signal validates but never reaches the wire, mirroring // the inference package's own Teach posture test from the federated gate's vantage. func TestReachabilityGateFlagOffTeachTransmitsNothing(t *testing.T) { var transmitted int32 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { atomic.AddInt32(&transmitted, 1) w.WriteHeader(http.StatusAccepted) })) defer srv.Close() c, err := inference.New(inference.Config{ BaseURL: srv.URL, Dimension: 384, Timeout: 2 * time.Second, TeachingEnabled: false, // the in tenant LIVE posture: validate the boundary, transmit nothing }) if err != nil { t.Fatalf("inference client: %v", err) } // Register the version this signal sits on so the scrub boundary accepts it (the same seam the producer uses // at init); the boundary refuses any unregistered version, so a test that speaks one must register it. scrub.RegisterModelVersion("v1.4.0") clean := scrub.TeachingSignal{ Pattern: "adjacent_skill_substitution_outcome", Band: scrub.BandHigh, Outcome: scrub.OutcomeApproved, Observations: 10, Successes: 7, ModelVersion: "v1.4.0", } if err := c.Teach(context.Background(), clean); err != nil { t.Fatalf("a clean signal must pass the boundary: %v", err) } if atomic.LoadInt32(&transmitted) != 0 { t.Fatal("with teaching disabled the signal must not be transmitted, no federated emission path is live") } }