package signedjobs import ( "context" "encoding/json" ) // ExecutorChain dispatches a verified signed op to the first sub-executor that OWNS it. A sub- // executor returns ErrNoExecutor for an op class it does not handle; the chain then tries the next. // If no sub-executor owns the op, the chain returns ErrNoExecutor so the runner leaves the job // queued for a later slice (the same contract a single executor has). The chain adds no policy — the // gate has already verified+bound the op before any Execute runs. type ExecutorChain []Executor // Execute implements Executor by trying each sub-executor in order. func (c ExecutorChain) Execute(ctx context.Context, op string, params json.RawMessage) error { for _, e := range c { err := e.Execute(ctx, op, params) if errorsIs(err, ErrNoExecutor) { continue // this sub-executor doesn't own the op — try the next } return err // owned (handled or failed) — done } return ErrNoExecutor // no sub-executor owns this op class in this build }