Repository navigation
atenet: classify a 403 route outcome as denied, not resume_error - #2534
Merged
Tim Hockin (thockin) merged 1 commit intoOct 23, 2026
Merged
Tim Hockin (thockin) merged 1 commit into
Tim Hockin (thockin) merged 1 commit into
Conversation
classifyOutcome maps a ReqError by its HTTP status, and a 403 had no case, so it fell through to resume_error, which the registry describes as a router defect. Every egress policy refusal (a destination outside the actor's policy, no policy, an actor that is not running, an invalid actor certificate) and every ingress PermissionDenied therefore counted as resume_error on atenet.router.route.duration: an alert on router defects fired on ordinary policy decisions, and a real resume failure hid among them. A 403 ReqError and a PermissionDenied status now record the new outcome denied. resume_error is left for a resume that failed for any other reason. The registry, the ateattr comment and docs/observability.md list the new value; the unavailable outcome no longer names a denied egress request among its examples, since a denial answers 403.
Merged
3 tasks done
Tim Hockin (thockin)
approved these changes
Oct 13, 2026
Tim Hockin (thockin)
enabled auto-merge
October 13, 2026 16:09
auto-merge was automatically disabled
October 21, 2026 23:19
Pull request was closed
Merged
via the queue into
agent-substrate:main
with commit Oct 23, 2026
4ebd668
24 of 25 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
classifyOutcomeincmd/atenet/internal/router/extproc/metrics.gomaps aReqErrorby its HTTP status: 404 →not_found, 503 →unavailable, 504 →timeout, 429 →rate_limited. A 403 has no case and falls through toresume_error, which the registry describes as "the resume failed for a different reason. The router has a defect." Every egress policy refusal (destination outside the policy, no policy, actor not running, invalid actor certificate) and every ingressPermissionDeniedtherefore recordsate.router.outcome=resume_erroronatenet.router.route.duration, so an alert on router defects fires on ordinary policy decisions and a real resume failure hides among them.Change
ate.router.outcomevaluedenied(ateattr.RouterOutcomeDenied): a 403ReqErrorand aPermissionDeniedstatus classify asdenied; everything else keeps its outcome, andresume_erroris left for a resume that failed for any other reason.docs/metrics/registry/metrics.yaml), theateattrcomment and the outcome list indocs/observability.mdlistdenied. Theunavailableoutcome no longer names a denied egress request among its examples, since a denial answers 403.Testing
metrics_test.go:PermissionDenied, a bare 403 and a 403 wrapping an uncoded cause classify asdenied; an uncoded error, anInternalstatus and a 500ReqErrorstill classify asresume_error.go test ./cmd/atenet/internal/router/extproc/ ./internal/ateattr/,hack/verify/golangci-lint.sh,hack/verify/metrics.sh.This PR was written by an AI agent on behalf of the author.