Skip to content

some ergonomic fixes for site level workflows#83

Draft
zsblevins wants to merge 1 commit into
mainfrom
zb/misc-ergonomic
Draft

some ergonomic fixes for site level workflows#83
zsblevins wants to merge 1 commit into
mainfrom
zb/misc-ergonomic

Conversation

@zsblevins

@zsblevins zsblevins commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Description

Slated for 1.3.1 release

  • Add guidance for agents for site level workflows
  • Make only Site and Status required on the UI for all site-level flows
  • Clean up error messages for bad graphql input
  • Remove bad defaults

Validation

  • Standard CI passes.
  • Kind integration passes, or this PR explains why it was not run.

The kind integration test is manual due to taking ~30 min to complete. When the PR is ready for review,
run Actions -> Kind Integration -> Run workflow against the copy-pr-bot generated
pull-request/<PR_NUMBER> branch. Use the default test_path for the full suite,
or narrow it only while debugging.

Passing Kind Integration run:

Checklist

  • I am familiar with the contributing guidelines in CONTRIBUTING.md.
  • Commits are signed off for DCO compliance.
  • New or existing tests cover these changes, or the PR explains why tests are not needed.
  • Documentation is updated for user-facing behavior changes.
  • Generated artifacts are updated when applicable, such as OpenAPI specs,
    docs screenshots, or Helm/rendered outputs.

Summary by CodeRabbit

  • New Features

    • Workflow forms now support a new “Provisioned” device status and default to Active/Provisioned when no status is selected.
    • Site-level workflow prompts now appear more clearly in workflow tool descriptions.
  • Bug Fixes

    • Improved handling of device filtering so invalid filters now show a clear failure message instead of breaking workflows.
    • Device searches and validations now better respect managed-only filtering.
  • UI

    • Workflow forms now treat tenant as optional and preserve query-based selections more reliably.

Signed-off-by: Zoe Blevins <zblevins@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds managed_only GraphQL device filtering through NautobotClient, wires it into site-level workflow activities (cable validation, password rotation, hardware validation), standardizes default statuses to ["Active", "Provisioned"], makes tenant and roles optional, adds MCP tool_prompt guidance for site-level workflows, and adds invalid-filter error handling with early-exit in hardware validation. UI forms, types, and e2e tests are updated accordingly.

Changes

Managed-only filtering, default statuses, optional tenant, MCP tool prompt, and invalid-filter handling

Layer / File(s) Summary
NautobotClient: managed_only filter and non-retryable GraphQL errors
src/nv_config_manager/temporal/client/nautobot.py, src/tests/temporal/ngc/activities/test_nautobot.py
graphql_query now raises ApplicationError(non_retryable=True) on NautobotException. _build_device_filter_variables and get_devices gain a managed_only parameter wired into the GraphQL query as $managed_only: Boolean / nv_config_manager_device_status. Tests verify non-retryable behavior and managed_only variable propagation.
Activity and workflow input contracts
src/nv_config_manager/temporal/ngc/activities/nautobot.py, src/nv_config_manager/temporal/ngc/workflows/cable_validation.py, src/nv_config_manager/temporal/ngc/workflows/site_password_rotation.py, src/nv_config_manager/temporal/ngc/workflows/cumulus_hardware_validation.py
GetNetworkDevicesInput gains managed_only. Cable validation, password rotation, and hardware validation workflow inputs change tenant to `str
Hardware validation: invalid-filter detection and early-exit
src/nv_config_manager/temporal/ngc/workflows/cumulus_hardware_validation.py, src/tests/temporal/ngc/workflows/test_cumulus_hardware_validation_workflow.py
Adds format_filter_summary, is_device_filter_error, format_device_filter_error, and literal-parsing helpers. GetDevicesToValidateStageOutput gains invalid_filter: bool. get_devices_to_validate catches ActivityError and returns structured failure. run() marks downstream stages UNREACHABLE and returns HardwareValidationResult(success=False) when no devices are found. Tests add invalid-filter mock and a new workflow test case.
MCP tool_prompt for site-level workflows
src/nv_config_manager/mcp/workflows.py, src/nv_config_manager/mcp/tools.py, src/tests/mcp/test_tools.py, src/tests/mcp/test_workflows.py
Adds SITE_LEVEL_DEVICE_FILTER_PROMPT and DEFAULT_SITE_LEVEL_DEVICE_STATUS constants. MCPWorkflow gains optional tool_prompt field; tool_description appends it when set. _tool_prompt_for_input_class detects site-level input models. discover_mcp_workflows populates tool_prompt; normalize_workflow_parameters defaults status for site-level workflows. tools.py uses tool_description in docstring and registration. Tests verify prompt propagation and status defaulting.
UI forms, types, and e2e tests
ui/src/lib/workflow-defaults.ts, ui/src/types/data-table.types.ts, ui/src/app/workflows/*/form/*.tsx, ui/src/mocks/data/formData.ts, ui/tests/e2e/*.spec.ts
New DEFAULT_SITE_WORKFLOW_STATUSES = ["Active", "Provisioned"] constant. Workflow input types make tenant optional. All three site workflow forms update Zod schemas (roles/status optional, tenant optional with empty-string default), default status to DEFAULT_SITE_WORKFLOW_STATUSES, refactor validateAndSetValue with an emptyValue parameter, and send tenant as undefined when empty. Mock data adds Provisioned status entry. E2e tests reflect removed required-field constraints and new default status selections.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hoppity-hop through the filter fields,
managed_only=True is the flag that yields!
Tenant's now optional, roles start at none,
Provisioned and Active — defaults are done.
Invalid filters? We catch them with grace,
The rabbit hops on at a well-structured pace! 🌿

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is broadly related to the site-level workflow changes but is too vague to describe the main update clearly. Use a more specific title that mentions the key change, such as site-level workflow prompts, defaults, or device filtering.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch zb/misc-ergonomic

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/tests/mcp/test_workflows.py (1)

59-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider asserting site password rotation as well.

These tests cover run_site_cable_validation and run_cumulus_hardware_validation but not the site password rotation workflow, which is also a site-level flow per the PR. Adding it would catch the field-name detection gap flagged in workflows.py (_tool_prompt_for_input_class).

🤖 Prompt for 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.

In `@src/tests/mcp/test_workflows.py` around lines 59 - 87, The MCP workflow tests
currently validate only run_site_cable_validation and
run_cumulus_hardware_validation, but they should also cover the site password
rotation workflow since it is another site-level flow. Update
test_site_level_filter_workflows_include_mcp_targeting_prompt and
test_site_level_filter_workflows_default_reachable_statuses in test_workflows.py
to include the password rotation tool_name from discover_mcp_workflows(),
asserting it gets SITE_LEVEL_DEVICE_FILTER_PROMPT and
DEFAULT_SITE_LEVEL_DEVICE_STATUS where appropriate. This will exercise the
field-name detection path in _tool_prompt_for_input_class and catch the missing
site-level handling.
🤖 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 `@src/nv_config_manager/mcp/workflows.py`:
- Around line 120-121: The status defaulting in workflows.py is treating an
explicitly provided empty status list as missing. Update the logic in the
workflow input normalization path around _tool_prompt_for_input_class and
normalized["status"] so it checks for key presence instead of truthiness if
empty list should mean “no status filter”; otherwise keep the current behavior
intentionally.

In `@src/nv_config_manager/temporal/ngc/workflows/cumulus_hardware_validation.py`:
- Around line 962-973: The top-level message in cumulus_hardware_validation’s
device validation flow is falling back to a generic “No devices matched” string
even when get_devices_to_validate already produced the correct Cumulus-specific
display. Update the branch that sets message to always use
devices_to_validate_output.display for the no-devices case, and only use the
generic fallback when needed for truly empty/invalid-filter scenarios; keep the
logic anchored around get_devices_to_validate and the invalid_filter check.

---

Nitpick comments:
In `@src/tests/mcp/test_workflows.py`:
- Around line 59-87: The MCP workflow tests currently validate only
run_site_cable_validation and run_cumulus_hardware_validation, but they should
also cover the site password rotation workflow since it is another site-level
flow. Update test_site_level_filter_workflows_include_mcp_targeting_prompt and
test_site_level_filter_workflows_default_reachable_statuses in test_workflows.py
to include the password rotation tool_name from discover_mcp_workflows(),
asserting it gets SITE_LEVEL_DEVICE_FILTER_PROMPT and
DEFAULT_SITE_LEVEL_DEVICE_STATUS where appropriate. This will exercise the
field-name detection path in _tool_prompt_for_input_class and catch the missing
site-level handling.
🪄 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: CHILL

Plan: Enterprise

Run ID: 061c1e85-4038-46f5-ac7c-a3fe08b5fc2d

📥 Commits

Reviewing files that changed from the base of the PR and between d5a1ef1 and 8c73f07.

📒 Files selected for processing (19)
  • src/nv_config_manager/mcp/tools.py
  • src/nv_config_manager/mcp/workflows.py
  • src/nv_config_manager/temporal/client/nautobot.py
  • src/nv_config_manager/temporal/ngc/activities/nautobot.py
  • src/nv_config_manager/temporal/ngc/workflows/cable_validation.py
  • src/nv_config_manager/temporal/ngc/workflows/cumulus_hardware_validation.py
  • src/nv_config_manager/temporal/ngc/workflows/site_password_rotation.py
  • src/tests/mcp/test_tools.py
  • src/tests/mcp/test_workflows.py
  • src/tests/temporal/ngc/activities/test_nautobot.py
  • src/tests/temporal/ngc/workflows/test_cumulus_hardware_validation_workflow.py
  • ui/src/app/workflows/cumulushardwarevalidationworkflow/form/cumulus-hardware-validation-form.tsx
  • ui/src/app/workflows/sitecablevalidationworkflow/form/site-cable-validation-workflow-form.tsx
  • ui/src/app/workflows/sitepasswordrotationworkflow/form/site-password-rotation-workflow-form.tsx
  • ui/src/lib/workflow-defaults.ts
  • ui/src/mocks/data/formData.ts
  • ui/src/types/data-table.types.ts
  • ui/tests/e2e/cumulusHardwareValidationForm.spec.ts
  • ui/tests/e2e/siteCableValidationForm.spec.ts

Comment on lines +120 to +121
if _tool_prompt_for_input_class(workflow.input_class) and not normalized.get("status"):
normalized["status"] = DEFAULT_SITE_LEVEL_DEVICE_STATUS.copy()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

status default skipped on explicit empty list.

not normalized.get("status") treats an explicitly supplied status=[] as missing and overrides it with DEFAULT_SITE_LEVEL_DEVICE_STATUS. If a caller intends "no status filter," that intent is lost. If empty-means-default is intended, this is fine; otherwise prefer a presence check ("status" not in normalized).

🤖 Prompt for 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.

In `@src/nv_config_manager/mcp/workflows.py` around lines 120 - 121, The status
defaulting in workflows.py is treating an explicitly provided empty status list
as missing. Update the logic in the workflow input normalization path around
_tool_prompt_for_input_class and normalized["status"] so it checks for key
presence instead of truthiness if empty list should mean “no status filter”;
otherwise keep the current behavior intentionally.

Comment on lines +962 to +973
filter_summary = format_filter_summary(
workflow_input.site,
workflow_input.roles,
workflow_input.status,
workflow_input.tenant,
workflow_input.device_type_ids,
)
message = (
devices_to_validate_output.display
if devices_to_validate_output.invalid_filter
else f"No devices matched the hardware validation filter ({filter_summary})."
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Top-level message can be inaccurate when devices matched but none were Cumulus.

When result.devices is non-empty but no Cumulus devices match, get_devices_to_validate returns devices=[] with invalid_filter=False and a precise display ("No Cumulus Linux devices matched..."). Here that branch falls through to the generic "No devices matched the hardware validation filter", which is misleading since devices did match the filter. The stage output already holds the correct message in devices_to_validate_output.display.

Proposed fix
-            message = (
-                devices_to_validate_output.display
-                if devices_to_validate_output.invalid_filter
-                else f"No devices matched the hardware validation filter ({filter_summary})."
-            )
+            message = devices_to_validate_output.display
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
filter_summary = format_filter_summary(
workflow_input.site,
workflow_input.roles,
workflow_input.status,
workflow_input.tenant,
workflow_input.device_type_ids,
)
message = (
devices_to_validate_output.display
if devices_to_validate_output.invalid_filter
else f"No devices matched the hardware validation filter ({filter_summary})."
)
filter_summary = format_filter_summary(
workflow_input.site,
workflow_input.roles,
workflow_input.status,
workflow_input.tenant,
workflow_input.device_type_ids,
)
message = devices_to_validate_output.display
🤖 Prompt for 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.

In `@src/nv_config_manager/temporal/ngc/workflows/cumulus_hardware_validation.py`
around lines 962 - 973, The top-level message in cumulus_hardware_validation’s
device validation flow is falling back to a generic “No devices matched” string
even when get_devices_to_validate already produced the correct Cumulus-specific
display. Update the branch that sets message to always use
devices_to_validate_output.display for the no-devices case, and only use the
generic fallback when needed for truly empty/invalid-filter scenarios; keep the
logic anchored around get_devices_to_validate and the invalid_filter check.

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