fix(harness): JSON-safe SLO state, unscored AI errors, mark recorded-only proposals executed

This commit is contained in:
seon committed 2026-09-24 02:22:29 +09:00
1 parent 5daf13b669
commit de076a79e4
4 files changed
+45 -36

No files matched your search

+21 -21
View File
@@ -46,17 +46,18 @@ func (a *App) mimirScalar(ctx context.Context, expr string) (float64, error) {
}
// SLOState is one evaluation of experiment design 4.2 (probe 12 consecutive successes = min over 3m; p95 and 5xx ratio over 5m).
// Values are nil when the series is absent (JSON has no NaN).
type SLOState struct {
At time.Time `json:"at"`
ProbeMin3m float64 `json:"probe_min_3m"`
P95 float64 `json:"p95_s"`
ErrorRatio float64 `json:"error_ratio"`
ProbeOK bool `json:"probe_ok"`
LatencyOK bool `json:"latency_ok"`
ErrorsOK bool `json:"errors_ok"`
Recovered bool `json:"recovered"`
MissingData []string `json:"missing_data,omitempty"`
QueryErrors []string `json:"query_errors,omitempty"`
At time.Time `json:"at"`
ProbeMin3m *float64 `json:"probe_min_3m"`
P95 *float64 `json:"p95_s"`
ErrorRatio *float64 `json:"error_ratio"`
ProbeOK bool `json:"probe_ok"`
LatencyOK bool `json:"latency_ok"`
ErrorsOK bool `json:"errors_ok"`
Recovered bool `json:"recovered"`
MissingData []string `json:"missing_data,omitempty"`
QueryErrors []string `json:"query_errors,omitempty"`
}
const (
@@ -67,25 +68,24 @@ const (
func (a *App) evaluateSLO(ctx context.Context) SLOState {
st := SLOState{At: time.Now().UTC()}
get := func(name, expr string) (float64, bool) {
get := func(name, expr string) *float64 {
v, err := a.mimirScalar(ctx, expr)
if err != nil {
st.QueryErrors = append(st.QueryErrors, name+": "+err.Error())
return math.NaN(), false
return nil
}
if math.IsNaN(v) {
st.MissingData = append(st.MissingData, name)
return v, false
return nil
}
return v, true
return &v
}
var ok bool
st.ProbeMin3m, ok = get("probe", qProbeMin3m)
st.ProbeOK = ok && st.ProbeMin3m >= 1 // the probe series must exist: no data is not recovery
st.P95, ok = get("p95", qP95)
st.LatencyOK = !ok || st.P95 < 0.5 // no traffic in the window (no k6) counts as within SLO
st.ErrorRatio, ok = get("errors", qErrRatio)
st.ErrorsOK = !ok || st.ErrorRatio < 0.01
st.ProbeMin3m = get("probe", qProbeMin3m)
st.ProbeOK = st.ProbeMin3m != nil && *st.ProbeMin3m >= 1 // the probe series must exist: no data is not recovery
st.P95 = get("p95", qP95)
st.LatencyOK = st.P95 == nil || *st.P95 < 0.5 // no traffic in the window (no k6) counts as within SLO
st.ErrorRatio = get("errors", qErrRatio)
st.ErrorsOK = st.ErrorRatio == nil || *st.ErrorRatio < 0.01
st.Recovered = st.ProbeOK && st.LatencyOK && st.ErrorsOK && len(st.QueryErrors) == 0
return st
}