fix(recovery,observability): stop misclassifying JSON-parse adapter failures, add queued-run-age gauge (BLO-21116) - #1019
Conversation
…ailures, add queued-run-age gauge (BLO-21116) Two independent fixes for runs stranding in `queued` on healthy agents, both scoped to what could be validated without touching the live dispatcher/scheduler: - classifyAdapterFailureForRecovery no longer matches CONFIGURATION_INCOMPLETE_ERROR_RE against the full raw resultJson blob when the adapter's own error names a response-parse failure. Before this, a truncated/malformed adapter response could false-positive match a config phrase inside its own untrusted payload text and latch the issue into `manual_repair_required` -- a dead end with no automatic retry, telling the owner to bind a secret that was never missing (observed on BLO-18991). - New paperclip_queued_run_oldest_age_seconds gauge (per agent_id, reset-then-set every /metrics scrape) plus a PrometheusRule alert and runbook, so a `queued` run stranding on an agent is visible instead of looking like ordinary in-progress work with an active run. Root-caused but NOT fixed here: dispatchRank's anti-starvation aging (server/src/services/heartbeat.ts, BLO-16253) caps a non-critical run's escalated rank at 2, one tier below fresh critical-priority work "no matter how long" it has waited. Reproduced live on BLO-20725: its queued run (00fb7575) sat 15h33m on the CTO agent, which stayed at exactly 5/5 running pods the whole time. That is a real fairness gap, not this diff's fix -- it needs care in a hot, heavily-tested scheduler path and is filed as a follow-up rather than rushed. Co-Authored-By: Paperclip <noreply@paperclip.ing>
1 similar comment
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Important Issues (3)
Strengths
Recommended Action
Because this PR is authored by |
Confirmed metric-contract bug:
|
…ueue-entry time, not createdAt (BLO-21116) Ally's review on onprem-k8s#2013 correctly flagged that refreshQueuedRunAgeMetrics aged its gauge off heartbeatRuns.createdAt, and promoteScheduledRetryRun's scheduled_retry -> queued transition never reset that timestamp -- so a run promoted after hours of retry backoff would instantly report its full lifetime as dispatch-queue wait, manufacturing exactly the false-stranded-run signal BLO-21116 exists to kill. Adds a nullable heartbeat_runs.queued_at column (metadata-only ADD COLUMN, no default -- not a table rewrite). It is stamped only by the two transitions that put an *existing* row back into `queued` after it was something else: promoteScheduledRetryRun (scheduled_retry -> queued) and deferRunForK8sIsolationConflict (running -> queued, BLO-21256). A fresh `queued` insert leaves it null and falls back to createdAt via COALESCE, which is already correct for a brand-new row. Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
Pushed
This closes the remaining Important finding on |
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Important Issues (2)
Suggestions (1)
Strengths
Recommended Action
Because this PR is authored by |
… gauge/alert (BLO-21116) Two Important findings from the PR #1019 review round, both real: - classifyAdapterFailureForRecovery excluded resultJson from the search string for a response-parse-failure adapter_failed, but not rawError -- so a truncated payload containing a quota phrase ("quota exceeded", "model is at capacity") still matched PROVIDER_QUOTA_ERROR_RE and misclassified as provider_quota, scheduling a retry-at-reset-time backoff for a transient parse fault with no real quota reset. Gate the whole quota branch on isResponseParseFailure the same way the configuration_incomplete branch already is. - deploy/helm/paperclip/templates/prometheusrule.yaml's no-op mirror copy of PaperclipQueuedRunStranded still paired a 1800s threshold with a 5m for:, stacking to a 35m first-fire past this issue's own ~30m AC -- the same defect already fixed on the Blockcast/onprem-k8s#2013 side but not here. Lowered to 1440s to match, and strengthened the Helm test to assert the combined threshold+for delay instead of each independently, which is exactly the gap that let 1800+5m through in the first place. Verification: - server/src/services/recovery/provider-failure-classification.test.ts: new case asserting a quota-phrase-bearing parse-failure classifies as null, not provider_quota. Logic re-verified standalone against the exact regexes (this repo's vitest suite needs CI's embedded Postgres + fresh install; not run locally, per project convention). - deploy/helm/paperclip/tests/prometheus-rule.test.mjs: all 7 cases pass locally (`node --test`), including the strengthened PaperclipQueuedRunStranded case. - `helm lint deploy/helm/paperclip -f values.blockcast.yaml --set prometheusRule.enabled=true` clean. Refs BLO-21116. Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
|
Pushed 1. Quota-misclassification collateral bug ( 2. Helm mirror-copy alert timing ( Full-suite verification is CI's Source issue: https://paperclip.blockcast.net/BLO/issues/BLO-21116 |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (2)
Important Issues (1)
Strengths
Recommended Action
Because this PR is authored by |
allyblockcast
left a comment
There was a problem hiding this comment.
Approved after PR-template gate repair; review gate and non-e2e CI are green, with e2e rerun still pending.
# Conflicts: # packages/db/src/migrations/meta/_journal.json
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (1)
Important Issues (2)
Strengths
Recommended Action
Because this PR is authored by |
Thinking Path
Linked Issues or Issue Description
What Changed
classifyAdapterFailureForRecoveryno longer runs the configuration-incomplete regex over the full rawresultJsonblob when the adapter error is a response-parse failure.paperclip_queued_run_oldest_age_seconds, keyed by agent, from a live oldest queued-run aggregate.PaperclipQueuedRunStrandedPrometheus rule, chart test coverage, and runbook guidance.onprem-k8smonitoring update and manual sync.Verification
server/src/services/recovery/provider-failure-classification.test.tsadds JSON-parse and genuine-configuration-failure classification cases. Not run locally in the original agent sandbox; covered by CI server tests.server/src/__tests__/metrics-service.test.tsadds queued-run-oldest-age metric coverage. Not run locally in the original agent sandbox; covered by CI server tests.node --test deploy/helm/paperclip/tests/prometheus-rule.test.mjspassed locally in the original PR work.helm lint deploy/helm/paperclip -f values.blockcast.yaml --set prometheusRule.enabled=truepassed locally in the original PR work.Risks
onprem-k8srule update because the in-repo chart copy is not the deployed rule source.Model Used
Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue templateCo-Authored-By: Paperclip noreply@paperclip.ing