Skip to content

feat(actions): HPA/VPA right-sizing audit with Datadog percentiles and Slack review card - #593

Merged
damianloch merged 17 commits into
mainfrom
sms10221/dev-1415-hpavpa
Aug 4, 2026
Merged

feat(actions): HPA/VPA right-sizing audit with Datadog percentiles and Slack review card#593
damianloch merged 17 commits into
mainfrom
sms10221/dev-1415-hpavpa

Conversation

@isiddharthsingh

@isiddharthsingh isiddharthsingh commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Adds a scheduled action that compares real Datadog usage against the CPU/memory requests, limits, and HPA maxReplicas declared in a team's IaC, opens one PR per materially mis-sized workload, and posts a Slack card with View PR and Dismiss. Aurora never applies anything — the PR is the change and a human merges it.

Seeded enabled=False, so nothing runs on a schedule until someone turns it on.

What's here

  • metric_stats Datadog resource type — Datadog has no time-percentile capability (every documented route is rejected or silently returns zero series, and both target metrics are gauges), so p95 is computed in Python from rolled-up points, behind a _P95_BY_SOURCE dispatch seam with an import-time guard. Returns one compact row per series rather than a single fat dict: _truncate_results keeps a prefix, so today a 973 KB metrics payload becomes count: 0, which is indistinguishable from "no data" and would lead the agent to cut an idle-looking workload. Budgeted at 30 KB against PASS_THROUGH_CHARS (40 K), not MAX_OUTPUT_SIZE (120 K) — above that an LLM summarizer paraphrases percentiles into plausible fiction.
  • hpa_vpa_recommendations table + RLS, with a partial unique index enforcing at most one live proposal per workload.
  • Lifecycle module owning all table access plus close_pull_request as a provider dispatch (GitHub implemented; GitLab/Bitbucket are a table entry each, not a migration — hence the vcs_provider column).
  • Card toolssend_hpa_vpa_recommendation (first agent-callable Slack write tool in the repo) and list_hpa_vpa_recommendations, so the prompt checks cooldown state before opening a PR.
  • Dismiss handler — closes the PR and starts a 30-day cooldown, then rewrites the card with the buttons removed.
  • Prompt + registration — generic; it discovers the metrics and VCS providers rather than assuming them.

Design decisions worth review

  • Dismiss is DB-first, then GitHub. A GitHub failure leaves the rec dismissed with the PR open — deliberate. We never nag about a workload a human rejected, and a stale open PR is visible and closable by hand. GitHub-first would risk closing the PR then losing the cooldown.
  • A merged PR is acceptance, not rejection — status merged, no cooldown, or the next genuine drift goes unreported.
  • First requests.patch in server/. MCP update_pull_request is allowlisted in mcp_tools.py but absent from tool_registry.py, so gate_action denies it in background context. Direct REST is the only reliable path.
  • No tool_registry.py entry and no gate_action call on the card tool. It writes only to Aurora's own RLS table and the channel Aurora created; a registry key would be a dead switch (_is_org_tool_permitted is only consulted inside gate_action, which this native tool never calls), and gate_action denies unconditionally in scheduled runs. The working kill switch is enabled=False on the action.
  • resource_type='metrics' behaviour is unchanged. Its output contract predates this work and the RCA prompts depend on it; only metric_stats auto-picks an interval. A test pins that boundary.
  • Asymmetric sizing rules live in the prompt because they're judgement, not mechanism: memory decreases check observed max (not p95) because the failure mode is an OOM-kill; CPU is symmetric because throttling is recoverable.

Verification

  • 341 tests pass (84 new feature tests; tests/architectural/ unchanged at 67).
  • Triggered the action end-to-end twice against the live stack: clean success runs, and the agent independently built sum:kubernetes.{cpu.usage.total,memory.usage}{*} by {kube_deployment} — the intended sum-across-pods shape — then wrote the living document and correctly issued no recommendations rather than inventing any.
  • Card path exercised live: posted, then updated in place on the same row (no duplicate); cooldown suppression and the materially-worse breakthrough both confirmed; double-click Dismiss is a no-op with dismissed_at unchanged; merge clears the cooldown; a duplicate live claim is blocked by the partial unique index.
  • /slack/interactions: valid signature → 200, bad signature → 403, stale timestamp → 403, malformed UUID → 200 with a clean message.

Two bugs found in review and fixed with regression tests: a NaN metric point silently broke list.sort() and understated max (which guards the OOM rule), and Dismiss closed the PR as the clicker rather than the account that opened it, which would have failed for any org-mate without their own GitHub connection.

Summary by CodeRabbit

  • New Features

    • Added HPA/VPA right-sizing audits with pull-request recommendations.
    • Added Slack recommendation cards with View PR and Dismiss actions, cooldown handling, and status updates.
    • Added Datadog metric statistics, including percentile summaries and configurable query intervals.
    • Added recommendation tracking to prevent duplicate or excessive notifications.
  • Bug Fixes

    • Read-only Ask mode now blocks recommendation-sending actions.
    • Improved handling and messaging for truncated or unusable Datadog results.
  • Documentation

    • Expanded Datadog guidance, supported resource types, interval behavior, and metric interpretation.

Replaces #592, which GitHub auto-closed when the branch was renamed. Same commits, same head SHA (693be8c6); no code changed.

@isiddharthsingh
isiddharthsingh requested a review from a team as a code owner July 30, 2026 15:50
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@isiddharthsingh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8d96feea-3fba-42df-8230-d6621fec20e8

📥 Commits

Reviewing files that changed from the base of the PR and between a21e074 and a8f11ff.

📒 Files selected for processing (1)
  • server/tests/chat/test_hpa_vpa_card_blocks.py

Walkthrough

Adds Datadog metric_stats querying and interval controls. It introduces persisted HPA/VPA recommendations with Slack cards, dismissal workflows, PR closure, database storage, system-action wiring, access control, and test coverage.

Changes

Datadog metrics and query handling

Layer / File(s) Summary
Metric statistics and interval contract
server/chat/backend/agent/tools/datadog_tool.py, server/chat/backend/agent/skills/integrations/datadog/SKILL.md, server/chat/backend/agent/tools/cloud_tools.py, server/tests/chat/test_datadog_metric_stats.py
Adds metric_stats, interval clamping and selection, percentile summaries, provider dispatch, truncation metadata, right-sizing guidance, and tests for malformed, null, non-finite, and capped data.

Recommendation lifecycle

Layer / File(s) Summary
Persistence, scoring, cooldowns, and PR closure
server/services/actions/hpa_vpa_recommendations.py, server/utils/db/db_utils.py, server/tests/services/test_hpa_vpa_recommendations.py
Adds recommendation states, workload locking, severity scoring, cooldown handling, RLS-backed storage, timestamp migration, GitHub PR closure, and lifecycle tests.

Right-sizing action and Slack tools

Layer / File(s) Summary
System action and agent tool integration
server/services/actions/hpa_vpa_action.py, server/services/actions/system_actions.py, server/chat/backend/agent/tools/hpa_vpa_card_tool.py, server/chat/backend/agent/tools/cloud_tools.py, server/chat/backend/agent/access/mode_access_controller.py, server/chat/background/task.py, server/chat/backend/agent/utils/state.py, server/tests/chat/test_hpa_vpa_card_blocks.py
Adds the right-sizing audit instructions, system-action seeding, validated Slack card tools, action-specific tool registration and state, Ask-mode blocking, and card-rendering tests.
Slack dismissal workflow
server/routes/slack/slack_events.py
Routes recommendation-card actions, authenticates dismissals, updates recommendation state, closes linked PRs, reports outcomes, and rewrites cards without dismissal controls.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • Arvo-AI/aurora#231: Both changes conditionally register agent tools in cloud_tools.py.
  • Arvo-AI/aurora#543: Both changes modify cloud-tool cache context and conditional registration.
  • Arvo-AI/aurora#592: The changes directly overlap the HPA/VPA, Datadog, Slack, and access-control implementation.

Suggested reviewers: beng360, oliviertrudeau

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant send_hpa_vpa_recommendation
  participant hpa_vpa_recommendations
  participant Slack
  Agent->>send_hpa_vpa_recommendation: submit right-sizing recommendation
  send_hpa_vpa_recommendation->>hpa_vpa_recommendations: claim or refresh recommendation
  send_hpa_vpa_recommendation->>Slack: post or update recommendation card
  Slack-->>send_hpa_vpa_recommendation: return message timestamp
  send_hpa_vpa_recommendation->>hpa_vpa_recommendations: attach Slack message
Loading
sequenceDiagram
  participant Slack
  participant _handle_hpa_vpa_dismiss
  participant hpa_vpa_recommendations
  participant close_pull_request
  Slack->>_handle_hpa_vpa_dismiss: submit dismiss action
  _handle_hpa_vpa_dismiss->>hpa_vpa_recommendations: transition recommendation to dismissed
  _handle_hpa_vpa_dismiss->>close_pull_request: close linked pull request
  close_pull_request-->>_handle_hpa_vpa_dismiss: return closure result
  _handle_hpa_vpa_dismiss->>Slack: rewrite card and send status
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: the HPA/VPA right-sizing audit, Datadog percentile support, and Slack review cards.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sms10221/dev-1415-hpavpa

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

arvo-ai-staging[bot]
arvo-ai-staging Bot previously approved these changes Jul 30, 2026

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review

Verdict: SAFE

No risks identified. This change looks safe to ship.


Aurora reviews PRs for incident prevention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/chat/backend/agent/access/mode_access_controller.py`:
- Line 88: Define one class-level constant for the read-only deny-list and
replace the duplicated literals in both filter_tools and is_tool_allowed with
that shared constant, ensuring both Ask-mode checks remain synchronized.

In `@server/chat/backend/agent/skills/integrations/datadog/SKILL.md`:
- Line 30: Add a blank line immediately after each new Resource Types heading
and the other three affected ### headings in SKILL.md, before their body
content, to satisfy markdownlint MD022. Preserve the existing heading text and
surrounding content.

In `@server/chat/backend/agent/tools/hpa_vpa_card_tool.py`:
- Around line 363-416: The cooldown handling inside the main database workflow
should be extracted to reduce cognitive complexity. Add a helper named
_check_cooldown(cur, org_id, workload_key, severity, workload) returning the
suppression JSON string or None, move the existing cooldown lookup, superseding,
logging, and response construction into it, then call it before
get_live_recommendation and return immediately when it yields a response while
preserving claim/post ordering.
- Around line 483-492: The _update_existing flow must keep the recommendation’s
VCS provider consistent when refreshing an existing record. Update the
refresh_recommendation call and its implementation to propagate the current
vcs_provider, or validate it against live["vcs_provider"] before refreshing;
ensure repo_full_name and pr_number are never updated while the stored provider
remains stale.

In `@server/routes/slack/slack_events.py`:
- Around line 680-717: Add a programmatic Casbin permission check for
clicker_user_id in the Slack dismissal flow, using the same permission predicate
as the actions/PR surface, before calling dismiss_recommendation. When the check
fails, send the ephemeral “not permitted” response and return without dismissing
or closing the PR; preserve the existing organization-ownership validation and
use the established authorization helper rather than adding a new manual role
check.
- Around line 719-733: The already_merged branch must track whether mark_merged
successfully clears the existing cooldown. Update the mark_merged handling and
status_line construction so success reports that no cooldown was applied, while
an exception reports that the accepted change remains subject to the existing
cooldown; preserve the current logging and transaction behavior.

In `@server/services/actions/hpa_vpa_recommendations.py`:
- Around line 326-351: Update the dismissal query and result mapping around the
returned-field tuple and `keys` so the SQL `RETURNING` column list is generated
from the single `keys` definition, preserving the existing field order. Zip the
returned row with `keys` using strict length validation to raise on mismatches
instead of silently truncating.

In `@server/tests/chat/test_datadog_metric_stats.py`:
- Line 276: Split the composite assertions checking serialized output into
separate assertions for “Infinity” and “NaN” at each referenced location,
preserving the existing validation while making failures identify the specific
forbidden value.

In `@server/utils/db/db_utils.py`:
- Around line 1445-1457: Update the table definition in the database schema
initialization to use TIMESTAMPTZ for dismissed_at and cooldown_until,
preserving the existing defaults and indexes. Ensure the recommendation
write/read paths, including dismiss_recommendation, get_active_cooldown, and
list_recommendations, continue using timezone-aware UTC values consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 52fccd80-e14d-46bc-8c1e-af2405285f49

📥 Commits

Reviewing files that changed from the base of the PR and between 8ceef9e and 693be8c.

📒 Files selected for processing (14)
  • server/chat/backend/agent/access/mode_access_controller.py
  • server/chat/backend/agent/skills/integrations/datadog/SKILL.md
  • server/chat/backend/agent/tools/cloud_tools.py
  • server/chat/backend/agent/tools/datadog_tool.py
  • server/chat/backend/agent/tools/github_rca_tool.py
  • server/chat/backend/agent/tools/hpa_vpa_card_tool.py
  • server/routes/slack/slack_events.py
  • server/services/actions/hpa_vpa_action.py
  • server/services/actions/hpa_vpa_recommendations.py
  • server/services/actions/system_actions.py
  • server/tests/chat/test_datadog_metric_stats.py
  • server/tests/conftest.py
  • server/tests/services/test_hpa_vpa_recommendations.py
  • server/utils/db/db_utils.py

Comment thread server/chat/backend/agent/access/mode_access_controller.py Outdated
Comment thread server/chat/backend/agent/skills/integrations/datadog/SKILL.md
Comment thread server/chat/backend/agent/tools/hpa_vpa_card_tool.py Outdated
Comment thread server/chat/backend/agent/tools/hpa_vpa_card_tool.py Outdated
Comment thread server/routes/slack/slack_events.py
Comment thread server/routes/slack/slack_events.py Outdated
Comment thread server/services/actions/hpa_vpa_recommendations.py
Comment thread server/tests/chat/test_datadog_metric_stats.py Outdated
Comment thread server/utils/db/db_utils.py Outdated
Comment thread server/chat/backend/agent/tools/cloud_tools.py
Comment thread server/chat/backend/agent/tools/datadog_tool.py Outdated
Comment thread server/utils/db/db_utils.py Outdated
Comment thread server/routes/slack/slack_events.py Outdated
Comment thread server/routes/slack/slack_events.py Outdated
Comment thread server/routes/slack/slack_events.py
Comment thread server/routes/slack/slack_events.py
Comment thread server/services/actions/hpa_vpa_recommendations.py
Comment thread server/services/actions/hpa_vpa_recommendations.py
Comment thread server/chat/backend/agent/tools/hpa_vpa_card_tool.py
Comment thread server/services/actions/hpa_vpa_action.py Outdated
Comment thread server/services/actions/hpa_vpa_action.py
…tion, server-derived severity, Slack feedback gaps

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/chat/backend/agent/skills/integrations/datadog/SKILL.md`:
- Around line 95-98: Update the fenced code block containing the Datadog metric
query examples to specify the text language tag, leaving the query expressions
unchanged.

In `@server/chat/backend/agent/tools/hpa_vpa_card_tool.py`:
- Around line 477-491: Update the recommendation-posting flow around the outer
try/except and _check_cooldown result so superseded_id is captured before
entering the try and remains available to error handling. In the outer exception
handler, call _restore_cooldown with the active connection/cursor and
superseded_id before returning the error response, while preserving the existing
_post_new and _post_new_for_existing compensation behavior.

In `@server/services/actions/hpa_vpa_recommendations.py`:
- Around line 244-250: Sanitize the untrusted dimension value in the
mismatched-units warning within the HpaVpa recommendations logic. Update the
logger.warning call to pass dimension through the module’s existing sanitize
helper while preserving the current message and value arguments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b0002f10-fd9e-494c-8737-cc250f1dccbb

📥 Commits

Reviewing files that changed from the base of the PR and between 693be8c and 02ce1d3.

📒 Files selected for processing (15)
  • server/chat/backend/agent/access/mode_access_controller.py
  • server/chat/backend/agent/skills/integrations/datadog/SKILL.md
  • server/chat/backend/agent/tools/cloud_tools.py
  • server/chat/backend/agent/tools/datadog_tool.py
  • server/chat/backend/agent/tools/hpa_vpa_card_tool.py
  • server/chat/backend/agent/utils/state.py
  • server/chat/background/task.py
  • server/routes/slack/slack_events.py
  • server/services/actions/hpa_vpa_action.py
  • server/services/actions/hpa_vpa_recommendations.py
  • server/tests/chat/test_datadog_metric_stats.py
  • server/tests/chat/test_hpa_vpa_card_blocks.py
  • server/tests/conftest.py
  • server/tests/services/test_hpa_vpa_recommendations.py
  • server/utils/db/db_utils.py

Comment thread server/chat/backend/agent/skills/integrations/datadog/SKILL.md Outdated
Comment thread server/chat/backend/agent/tools/hpa_vpa_card_tool.py
Comment thread server/services/actions/hpa_vpa_recommendations.py

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

Comment thread server/tests/chat/test_hpa_vpa_card_blocks.py Fixed

@arvo-ai-staging arvo-ai-staging 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.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@sonarqubecloud

sonarqubecloud Bot commented Aug 1, 2026

Copy link
Copy Markdown

@damianloch
damianloch merged commit 8d3c546 into main Aug 4, 2026
16 checks passed
@damianloch
damianloch deleted the sms10221/dev-1415-hpavpa branch August 4, 2026 14:19
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.

2 participants