feat(watchdog): Sentry flags + quarantine on above-band Jev verdicts (#44)
This commit is contained in:
1 parent
66cdd053f8
commit
084a4309d4
4 files changed
+198
-7
No files matched your search
@@ -313,6 +313,86 @@ func (f *Flock) ClassifyDivergence(ctx context.Context, state any, budgets ...*B
|
||||
return p, ok
|
||||
}
|
||||
|
||||
// watchdogQuestions is the Sentry's off-task check (E3, JEV_STRATEGIES
|
||||
// strategies 4 and 8): three crisp yes/no noul questions about one crow
|
||||
// message against the request it answers. noul carries no confidence, so the
|
||||
// probability itself is band-thresholded (strategy 3).
|
||||
var watchdogQuestions = map[string]any{
|
||||
"answers_request": map[string]any{
|
||||
"type": "noul",
|
||||
"instructions": "Does `message` actually deliver what `request` asked of `crow`?",
|
||||
"criteria": map[string]string{
|
||||
"true": "It answers the request, or plainly takes it on.",
|
||||
"false": "It talks around it, answers a different question, or is off-task.",
|
||||
},
|
||||
},
|
||||
"states_fact_without_source": map[string]any{
|
||||
"type": "noul",
|
||||
"instructions": "Does `message` assert a checkable fact while showing no source for it?",
|
||||
"criteria": map[string]string{
|
||||
"true": "It states a specific, checkable fact (a number, a quote, an event) with no stated source.",
|
||||
"false": "It is an opinion, a plan, or the facts it states are sourced.",
|
||||
},
|
||||
},
|
||||
"contradicts_earlier": map[string]any{
|
||||
"type": "noul",
|
||||
"instructions": "Does `message` contradict what the `earlier` delivers on the same request say?",
|
||||
"criteria": map[string]string{
|
||||
"true": "It disagrees with an earlier deliver on the same request.",
|
||||
"false": "It agrees with, or simply adds to, what `earlier` said.",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// ClassifyWatch asks the watchdog questions of one crow message and returns
|
||||
// each answer's noul probability. ok is false on transport error or a missing
|
||||
// answer (a noul answer always carries a probability).
|
||||
func (j *JevClient) ClassifyWatch(ctx context.Context, state any) (map[string]float64, bool) {
|
||||
if j == nil {
|
||||
return nil, false
|
||||
}
|
||||
answers, _, _, err := j.SystemOne(ctx, state, watchdogQuestions)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
scores := make(map[string]float64, len(watchdogQuestions))
|
||||
for name := range watchdogQuestions {
|
||||
a := answers[name]
|
||||
if a.Noul == nil {
|
||||
return nil, false
|
||||
}
|
||||
scores[name] = *a.Noul
|
||||
}
|
||||
return scores, true
|
||||
}
|
||||
|
||||
// ClassifyWatch runs the watchdog check under the flock guardrails (cap,
|
||||
// timeout, flight log with the three noul probabilities recorded for
|
||||
// calibration, strategy 5).
|
||||
func (f *Flock) ClassifyWatch(ctx context.Context, state any, budgets ...*Budget) (map[string]float64, bool) {
|
||||
if f.jev == nil {
|
||||
return nil, false
|
||||
}
|
||||
for _, b := range budgets {
|
||||
if err := b.Check(); err != nil {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
release, slot := f.reserve(ctx)
|
||||
if !slot {
|
||||
return nil, false
|
||||
}
|
||||
defer release()
|
||||
cctx, cancel := context.WithTimeout(ctx, f.g.CrowTimeout)
|
||||
defer cancel()
|
||||
start := time.Now()
|
||||
scores, ok := f.jev.ClassifyWatch(cctx, state)
|
||||
if f.log != nil {
|
||||
f.log.Write(Event{Kind: "watch", Crow: "Sentry", Model: f.jev.model, Ms: time.Since(start).Milliseconds(), Prob: scores})
|
||||
}
|
||||
return scores, ok
|
||||
}
|
||||
|
||||
// ClassifyKind tags a nest message under the same guardrails as any call:
|
||||
// flock cap, timeout and flight log, with the probabilities recorded.
|
||||
func (f *Flock) ClassifyKind(ctx context.Context, text string, budgets ...*Budget) (string, map[string]float64, bool) {
|
||||
|
||||
Reference in new issue
Block a user