seam sweep: move the TieredBackend witness into production code (no version bump)
A witness in a _test.go file fires on go test and go vet but NOT on go build alone — and a build-only step is exactly how the R-88 Part 2 near-miss would have shipped. Moved beside the type it pins, and added one for AgentVersionReporter. No defect found: quiesceBackend and *Client both satisfy their interfaces today. No version bump, no deploy — compile-time only.
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "gitea.dooplex.hu/admin/felhom-controller/internal/quiesce"
|
||||||
|
|
||||||
|
// COMPILE-TIME WITNESSES for OPTIONAL interfaces satisfied by a RUNTIME type assertion.
|
||||||
|
//
|
||||||
|
// Moved here from a _test.go file (R-88 Part 2) on purpose: a witness in a test fires on `go test`
|
||||||
|
// and `go vet`, but NOT on `go build` alone. The failure it guards against — a signature change that
|
||||||
|
// silently breaks an interface nobody checks at compile time — is exactly the kind that gets pushed
|
||||||
|
// by a build-only step.
|
||||||
|
//
|
||||||
|
// THE INCIDENT THIS PREVENTS, which already happened once: when `TieredBackend.DueFor` gained a
|
||||||
|
// return value during R-88 Part 2, `quiesceBackend` stopped satisfying the interface and the whole
|
||||||
|
// repo still BUILT AND VETTED CLEAN, because `resolveDueTiers` only ever asserts it at runtime
|
||||||
|
// (`l.backend.(TieredBackend)`). A failed assertion silently falls back to the untargeted
|
||||||
|
// single-tier path — so every box would have quietly lost R-82's multi-tier backups, with no error
|
||||||
|
// anywhere. It was caught by accident, not by the toolchain.
|
||||||
|
//
|
||||||
|
// THIS DOES NOT MAKE THE INTERFACE REQUIRED. Optionality is deliberate: it is what lets a new
|
||||||
|
// controller meet an old agent, and what `resolveDueTiers` degrades through on purpose. The witness
|
||||||
|
// pins the IMPLEMENTATION, not the CONTRACT.
|
||||||
|
var _ quiesce.TieredBackend = quiesceBackend{}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gitea.dooplex.hu/admin/felhom-controller/internal/quiesce"
|
|
||||||
)
|
|
||||||
|
|
||||||
// R-88 Part 2 — TieredBackend is satisfied by a RUNTIME type assertion in `resolveDueTiers`
|
|
||||||
// (`l.backend.(TieredBackend)`), NOT at compile time. So when DueFor's signature changed, the whole
|
|
||||||
// repo still built and vetted clean while `quiesceBackend` silently stopped satisfying the
|
|
||||||
// interface — which would have degraded every box to the untargeted single-tier path, losing R-82's
|
|
||||||
// multi-tier backups entirely, with no error anywhere.
|
|
||||||
//
|
|
||||||
// This compile-time assertion is the only thing that catches it. It caught it during R-88 Part 2.
|
|
||||||
// Do not delete it; a runtime-asserted interface needs a compile-time witness.
|
|
||||||
func TestQuiesceBackendSatisfiesTieredBackend(t *testing.T) {
|
|
||||||
var _ quiesce.TieredBackend = quiesceBackend{}
|
|
||||||
}
|
|
||||||
@@ -230,3 +230,9 @@ func classifySupportErr(err error) SupportState {
|
|||||||
}
|
}
|
||||||
return SupportUnknown
|
return SupportUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AgentVersionReporter witness. Asserted at SupportsWithSource (`p.(AgentVersionReporter)`); a failed
|
||||||
|
// assertion falls back from the version gate to the live probe. That degrade is benign — both paths
|
||||||
|
// decide correctly — but *Client is the production prober and losing the version path would silently
|
||||||
|
// turn every MinAgent floor into a probe round-trip, which is a behaviour change nobody would see.
|
||||||
|
var _ AgentVersionReporter = (*Client)(nil)
|
||||||
|
|||||||
Reference in New Issue
Block a user