a Hexis 401 says the token was refused, not that Hexis is down (V-587)
The vendored Hexis client is a separate implementation and returns a plain fmt.Errorf for every status at or above 400, so errors.As for *ecosystemError never matched, Unauthorized() was never consulted, and ecosystemGap always fell through to the outage line. A wrong token sent him to inspect a healthy service. hexisError classifies at Maven's boundary, since the client is vendored from another repo and a local edit there is lost on the next re-vendor. The status text is the only signal that survives the wrapping, so that is what it reads; anything unrecognised stays at status 0, which is what Unreachable() means. The correct fix is a typed error upstream carrying the code, and Maven cannot land it unilaterally. execHexis is the second site and it did not call ecosystemGap at all. It now does, but only for a failure that belongs to the service. An execution that Hexis accepted and that then failed keeps the command-level line: that is the command failing, not Hexis degrading, and calling it an outage would be the same defect pointed the other way. Authorization is unchanged: a 401 is still a refusal, it is not retried and nothing proceeds on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -551,6 +551,14 @@ func unauthorizedEcosystemError(err error) bool {
|
||||
return errors.As(err, &ee) && ee.Unauthorized()
|
||||
}
|
||||
|
||||
// isEcosystemError reports a failure that belongs to the service rather than to
|
||||
// what was asked of it: a call that never landed, or one the far side refused.
|
||||
// It separates "Hexis is down" from "the restart failed".
|
||||
func isEcosystemError(err error) bool {
|
||||
var ee *ecosystemError
|
||||
return errors.As(err, &ee)
|
||||
}
|
||||
|
||||
// traceErrorFields describes an ecosystemError for a trace without leaking the
|
||||
// payload: the HTTP status and the failure class, nothing else.
|
||||
func traceErrorFields(err error) map[string]any {
|
||||
@@ -777,6 +785,14 @@ func (h *reactiveHandler) execHexis(ctx context.Context, capID, capName, entityI
|
||||
mergeFields(traceErrorFields(err), map[string]any{
|
||||
"entity_id": entityID, "capability": capName, "causation_id": causationID,
|
||||
}))
|
||||
// Hexis never answering, or answering "no", is a gap in Hexis and is
|
||||
// named as one — a refused token said "не получилось выполнить команду"
|
||||
// here and sent him to debug a capability that was never reached
|
||||
// (Vikunja #587). An execution that genuinely ran and failed is not an
|
||||
// ecosystemError and keeps the command-level line.
|
||||
if isEcosystemError(err) {
|
||||
return ecosystemGap(serviceHexis, err)
|
||||
}
|
||||
return phraser.A(phraser.ActFailEntity, map[string]string{"name": displayName})
|
||||
}
|
||||
// One record per hop: the second write this used to make said the same
|
||||
|
||||
Reference in New Issue
Block a user