C0b: address verified gadfly findings (panic-safety + test honesty)
executus CI / test (pull_request) Failing after 58s
executus CI / test (pull_request) Failing after 58s
From PR #9 (minimax + deepseek): - Run now has a top-level recover() — the "never propagates a panic" promise was unenforced; a panicking host Port (Critic/Audit/Palette) on the run goroutine now becomes Result.Err instead of unwinding into the caller. - The critic deadline-watch goroutine recovers panics from a host Deadline() (it's a separate goroutine, so Run's recover can't catch it) — a buggy CriticHandle can't crash the process. - CriticHandle interface documents its concurrency contract (Record*/Steer on the run goroutine vs Deadline()/Stop() from the watch goroutine — impls must be concurrent-safe; the critic battery already is). - startCritic's dead `soft <= 0 -> noop` guard (withFallbacks already coerces to 90s) replaced with a defensive inline 90s default, so a bypass of withFallbacks still gets a working critic instead of silently none. - Delivery tests made honest: the old "error path" test only checked the early-return (no delivery); added TestDeliverErrorOnRunFailure (in-loop model error -> DeliverError to the target) + renamed the early-return test. Graded all #9 findings in the gadfly MCP. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+5
-1
@@ -33,7 +33,7 @@ func (e *Executor) startCritic(runCtx context.Context, cancel context.CancelFunc
|
||||
}
|
||||
soft := e.cfg.Defaults.CriticSoftTimeout
|
||||
if soft <= 0 {
|
||||
return nil, noop
|
||||
soft = 90 * time.Second // defensive: withFallbacks normally guarantees >0
|
||||
}
|
||||
h := e.cfg.Ports.Critic.Monitor(runCtx, info, soft)
|
||||
if h == nil {
|
||||
@@ -41,6 +41,10 @@ func (e *Executor) startCritic(runCtx context.Context, cancel context.CancelFunc
|
||||
}
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
// A host CriticHandle.Deadline() that panics must not crash the process
|
||||
// (this runs on its own goroutine, so the executor's top-level recover
|
||||
// can't catch it). Log-free best-effort: just stop watching.
|
||||
defer func() { _ = recover() }()
|
||||
t := time.NewTicker(criticDeadlineCheck)
|
||||
defer t.Stop()
|
||||
for {
|
||||
|
||||
Reference in New Issue
Block a user