Skip to content

feat(skill): argocd_sync_failed — diagnose stuck-degraded ArgoCD apps - #14

Merged
mashkovd merged 3 commits into
mainfrom
feat/argocd-sync-failed-skill
May 6, 2026
Merged

mashkovd merged 3 commits into
mainfrom
feat/argocd-sync-failed-skill

Conversation

@mashkovd

@mashkovd mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member

Summary

  • New built-in skill `argocd_sync_failed` covering Degraded apps with sync failure (distinct from `argocd_drift` which only handles benign OutOfSync+Healthy).
  • Skill recognizes two known recovery-drill signatures in app status `message`:
    • "must remain in spec.versions" / "missing from spec.versions" → CRD storedVersion conflict.
    • "request to convert CR from an invalid group/version" → managedFields poisoning.
  • Returns plain-text recovery commands (cluster-side kubectl, NOT auto-fixable). Telegram delivery handled by existing notify path; operator approves manually.
  • Wires AlertManager `ArgoCDApplicationDegraded` / `ArgoCDApplicationSyncFailed` (added in mctl-gitops PR feat(agents): issue-141-oomkilled-and-other-pod-scoped-skills-re #142) → `ticket.TypeArgoCDDegraded` so the new skill picks them up.

Why

`ArgoCDDriftSkill` only handles benign `OutOfSync+Healthy` drift. Apps stuck Degraded with a sync failure had no diagnostic skill — most painful case: `external-secrets` Application stuck Degraded for 6 days (2026-05-01 → 2026-05-07) with no proposed recovery, GitOps loop wedged across 11 child apps. See plan `~/.claude/plans/streamed-soaring-fox.md` and recovery drill `reference_eso_storedversion_recovery.md`.

Test plan

  • `go test ./...` passes.
  • `go vet ./...` clean.
  • `go build ./...` clean.
  • New table-driven test `TestArgoCDSyncFailedSkillMatch` covers: drift handoff (no match), Synced+Healthy (no match), OutOfSync+Degraded, both signature messages with priority 80, Degraded-only fallback, no-status.
  • `TestAllSkillsRegistered` updated (12 skills, includes `argocd_sync_failed`).
  • Smoke test in mctl-preprod after merge: trigger an ArgoCDApplicationDegraded alert (manual sync fail) → ticket created with `type=argocd_degraded` → `argocd_sync_failed` skill matches → diagnosis text in Telegram with recovery commands.

ArgoCDDriftSkill only handles benign OutOfSync+Healthy drift. Apps that
are Degraded with a sync failure had no diagnostic skill and silently
piled up TypeArgoCDDegraded tickets. Most painful instance: external-
secrets stuck Degraded for 6 days (2026-05-01 → 2026-05-07) while the
agent system never proposed any recovery — see plan
~/.claude/plans/streamed-soaring-fox.md.

The new skill matches OutOfSync+Degraded (priority 60), Degraded only
(priority 55), and bumps to priority 80 + HIGH confidence when the
status message contains a known recovery-drill signature:
  - "must remain in spec.versions" / "missing from spec.versions" →
    CRD storedVersion conflict (chart major-version revert long-tail)
  - "request to convert CR from an invalid group/version" →
    managedFields poisoning from a temp CRD recovery window

Diagnose() returns the exact recovery commands as plain text. Fix() is
intentionally nil — recovery is cluster-side kubectl, not a gitops PR,
so the diagnosis lands in Telegram for human approval.

Also wires AlertManager → ticket classification: the new
ArgoCDApplicationDegraded / ArgoCDApplicationSyncFailed alerts (added
in mctl-gitops PR #142) now map to TypeArgoCDDegraded in classifyAlert
so the new skill picks them up.
@mashkovd

mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 74ee766d7d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/monitor/alerthandler.go Outdated
Comment on lines +204 to +205
case "ArgoCDApplicationDegraded", "ArgoCDApplicationSyncFailed":
return ticket.TypeArgoCDDegraded, ticket.SeverityWarning

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve service identity for ArgoCD sync alerts

Mapping ArgoCDApplicationDegraded/ArgoCDApplicationSyncFailed to TypeArgoCDDegraded without also extracting the app name from alert labels causes these tickets to keep service from pod (or empty), even though processAlert currently only special-cases name for workflows (internal/monitor/alerthandler.go lines 88-97). In environments where these ArgoCD alerts do not carry an application pod label (or carry only ArgoCD controller pods), unrelated app incidents collapse into one dedupe key and collectEvidence skips argocd_status when service=="" (internal/pipeline/evidence.go lines 43-50), so the new argocd_sync_failed skill cannot diagnose the actual failing application.

Useful? React with 👍 / 👎.

Codex P1 on PR #14: ArgoCDApplicationDegraded /
ArgoCDApplicationSyncFailed alerts come from argocd-metrics with the
Application identity in `name` (and tenant in `dest_namespace`), not
in `pod`. processAlert was previously only special-casing `name` for
TypeWorkflowFailed, so every Degraded application collapsed onto the
same (tenant="", service="") dedup key. pipeline.collectEvidence then
skipped argocd_status entirely (gated on service != ""), so the new
argocd_sync_failed skill never saw the data it needed to diagnose.

This adds the equivalent special-case for TypeArgoCDDegraded plus a
table-driven test that asserts service=name and tenant=dest_namespace.
classifyAlert tests grow two new cases for the alert names themselves.
@mashkovd

mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

The companion mctl-gitops PR #142 renamed the alert from
ArgoCDApplicationSyncFailed to ArgoCDApplicationOutOfSyncLong after
Codex P2 (the alert fires on prolonged OutOfSync drift, not a
sync-failure signal). Add the new name to classifyAlert so the two
PRs stay merge-order-independent. The legacy name stays in the switch
until both PRs have landed and the chart has rolled out.
@mashkovd

mashkovd commented May 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@mashkovd
mashkovd merged commit 53e6168 into main May 6, 2026
1 check passed
@mashkovd
mashkovd deleted the feat/argocd-sync-failed-skill branch May 6, 2026 23:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant