Skip to content

feat(breakfix): BFX break-fix suite (BFX01-BFX06) with NICo coverage - #562

Open
abegnoche wants to merge 8 commits into
mainfrom
cursor/bfx-remediation-suite-4f18
Open

feat(breakfix): BFX break-fix suite (BFX01-BFX06) with NICo coverage#562
abegnoche wants to merge 8 commits into
mainfrom
cursor/bfx-remediation-suite-4f18

Conversation

@abegnoche

@abegnoche abegnoche commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

Adds the break-fix validation suite covering BFX01–BFX06, wired into the existing bare_metal and k8s suites rather than a standalone suite.

  • isvtest/validations/breakfix.py — 12 new validation classes (BFX03-01 reuses the existing BmHardwareSerialCheck)
  • suites/bare_metal.yaml — 11 checks; suites/k8s.yaml — GPU reset + cordon
  • my-isv — demo stubs for every step, exercised by make demo-test
  • nico — 4 read-only implementations; the rest emit a structured skip carrying a gap: BFXxx-yy marker rather than a vacuous pass

Validated against live NICo

Run on two independent NICo deployments: az51-dev3 (6 CPU-only machines) and az51-dev3-dh1 (18 GPU hosts).

Test Result
BFX03-01 hardware serials Pass — chassis/baseboard/CPU/NIC/GPU identifiers on all 18 GPU hosts
BFX02-03 repair history Pass — genuine Error history on 18/18 machines
BFX02-01 maintenance events Skip — neither site has maintenance events to observe
BFX01-01/02/03/05, BFX02-02, BFX03-02/03, BFX04-01, BFX05-01, BFX06-01 Skip — NICo gaps

The 8 gaps reproduced with identical reasons on both deployments, so they are platform gaps rather than one site's configuration. On NICo only BFX03-01 and BFX02-03 currently prove anything; the rest document missing API surface.

Every break-fix step reads only the machine resource, so the suite runs with infrastructure-scope access and needs no tenant-level API permissions.

Also in this PR

  • nico/config/key_access.yaml folded into bare_metal.yaml — both imported the same suite, which made --provider nico --suite bare_metal unresolvable. The key-provisioning steps carry skip: true so a routine run stays read-only.
  • BFX test-plan labels synced with the suite wiring (this was failing make test).
  • BFX02 checks now skip instead of passing when the provider returns no evidence, and InUse no longer counts as repair history.

Testing

make test (124 passed) · make demo-test · make lint · uvx pre-commit run -a · scripts/validate_suite_wiring.py --check

New checks are unreleased; run with ISVTEST_INCLUDE_UNRELEASED=1.

Issues

Closes #213 — observed passing against live NICo, on 18/18 machines at az51-dev3-dh1
Closes #211 — implemented against the NICo API; skipped only because no test site had a machine in maintenance

The rest get the test and wiring, but NICo cannot satisfy them yet, so they stay open:

Part of #207
Part of #208
Part of #210
Part of #212
Part of #214
Part of #215

#206 and #209 also stay open — both are wired into k8s.yaml and have not been exercised end-to-end.

#567 tracks each remaining NICo gap. #568 tracks the orphaned reset_gpus.py.

Summary by CodeRabbit

  • New Features
    • Added comprehensive break-fix validations for bare-metal environments, including maintenance, repairs, firmware, logs, replacements, health monitoring, and notifications.
    • Added Kubernetes workflows for GPU resets and node cordoning.
    • Added provider-specific workflows with demo support and structured results.
  • Documentation
    • Updated suite documentation with new break-fix validation steps and requirements.
  • Tests
    • Added coverage for successful, skipped, and failed break-fix validation scenarios.

@copy-pr-bot

copy-pr-bot Bot commented Jul 28, 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 Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4a9b8f3f-3449-4f7b-9bce-636a6cee02fb

📥 Commits

Reviewing files that changed from the base of the PR and between 2587d53 and b229d75.

📒 Files selected for processing (1)
  • isvtest/tests/test_breakfix.py

📝 Walkthrough

Walkthrough

Added BFX01–BFX06 validations for bare-metal and Kubernetes suites. Added NICo API-backed queries with structured gaps and my-isv demo templates. Added provider configuration, suite wiring, documentation, labels, and tests.

Changes

Break-fix validation contracts

Layer / File(s) Summary
Validation contracts and coverage
isvtest/src/isvtest/validations/breakfix.py, isvtest/tests/test_breakfix.py, isvctl/configs/suites/*.yaml, isvctl/configs/suites/README.md, docs/test-plan.yaml
Added BFX01–BFX06 checks, suite wiring, documentation, labels, and tests for pass, skip, and failure results.

NICo provider workflows

Layer / File(s) Summary
NICo configuration and shared results
isvctl/configs/providers/nico/config/bare_metal.yaml, isvctl/configs/providers/nico/scripts/breakfix/_common.py
Added break-fix configuration, optional SSH key setup and teardown, machine discovery, structured results, JSON output, and data normalization.
NICo break-fix query workflows
isvctl/configs/providers/nico/scripts/breakfix/*
Added maintenance, repair, diagnostic, notification, retirement, health-agent, and lifecycle scripts. Unsupported capabilities emit structured skip results.

my-isv provider workflows

Layer / File(s) Summary
my-isv break-fix templates
isvctl/configs/providers/my-isv/config/*.yaml, isvctl/configs/providers/my-isv/scripts/breakfix/*
Added break-fix test steps, shared demo/not-implemented handling, and executable query and lifecycle templates.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BareMetalConfig
  participant MaintenanceEvents
  participant CommonHelpers
  participant NICoREST
  participant MaintenanceEventsCheck
  BareMetalConfig->>MaintenanceEvents: invoke query command
  MaintenanceEvents->>CommonHelpers: list_site_machines
  CommonHelpers->>NICoREST: retrieve paginated site machines
  MaintenanceEvents->>MaintenanceEventsCheck: emit normalized event result
Loading

Possibly related issues

  • #567 — The PR adds NICo break-fix scripts and validation wiring. It represents unsupported NICo capabilities as structured skips.

Suggested reviewers: daluz

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The pull request also adds BFX01 and BFX03-BFX06 validations, providers, tests, and configuration unrelated to the linked issues [#211] and [#213]. Split unrelated BFX01 and BFX03-BFX06 changes into separate pull requests, or link issues that define those requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 78.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 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 addition of the BFX01-BFX06 break-fix suite and NICo coverage.
Linked Issues check ✅ Passed The changes implement BFX02-01 maintenance-event queries and BFX02-03 historical repair-status queries for the linked issues [#211] and [#213].
✨ 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 cursor/bfx-remediation-suite-4f18

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

@abegnoche
abegnoche force-pushed the cursor/bfx-remediation-suite-4f18 branch from 85d9bae to 52bc942 Compare July 30, 2026 15:23
@copy-pr-bot

copy-pr-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Introduce suites/remediation.yaml covering all open M8 break-fix issues
(BFX01-BFX06): validation classes, my-isv demo stubs, and NICo provider
wiring. Move BFX03-01 (HardwareSerialCheck) out of bare_metal into the
new plain suite with capability gating per PR #561.

NICo implements read-only observability where the tenant REST API exposes
signals (maintenance events, repair history, serial inventory). Mutating
lifecycle actions, GPUd/Sentinel/Maestro agents, NV switch firmware,
retirement notices, and tenant notification channels emit structured
skips with documented gap IDs.

Stacks on PR #561 (capability/requires model).

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Alexandre Begnoche <abegnoche@users.noreply.github.com>
@abegnoche
abegnoche force-pushed the cursor/bfx-remediation-suite-4f18 branch from 52bc942 to 4a7e1b9 Compare August 4, 2026 20:10
Break-fix is mostly bare-metal plus k8s-only cordon/GPU reset, so a plain
remediation suite is not justified the way storage is. Wire BM BFX into
bare_metal, k8s actions into k8s, and rename scripts/modules to breakfix.

Signed-off-by: Alexandre Begnoche <abegnoche@nvidia.com>
Both nico configs imported suites/bare_metal.yaml, so `--provider nico
--suite bare_metal` could not resolve and demanded an explicit -f. This was
the only such collision in the repo.

Fold key_access.yaml's setup/teardown steps into bare_metal.yaml and delete
the file. The test step was already identical in both; only the throwaway-key
provisioning was unique. Those two steps carry `skip: true` so a routine run
stays read-only -- setup_key_access mutates the site (POST sshkey +
sshkeygroup, best-effort PATCH of the SSH-key SOL flag), which should not be
a side effect of ordinary bare-metal validation. Unskip both to make
AUTH-XX-03 pass without a pre-synced key.

Signed-off-by: Alexandre Begnoche <abegnoche@nvidia.com>
The test-plan coverage guardrail requires each plan entry's labels to equal
the union of labels across the suite wirings declaring that test_id. Folding
the BFX checks into bare_metal.yaml and k8s.yaml added platform labels to the
wiring but not to docs/test-plan.yaml, leaving `make test` red on all 13 BFX
entries.

Add bare_metal to the eleven bare-metal entries, and kubernetes to BFX01-01
and BFX01-04, which live in the k8s suite. Also apply the pre-commit import
ordering and whitespace fixes the BFX commits missed.

Signed-off-by: Alexandre Begnoche <abegnoche@nvidia.com>
… checks

Against a live NICo site both checks passed while proving nothing.
events_queryable and history_queryable are set by the provider script the
moment the machine-list call succeeds, so MaintenanceEventsCheck passed with
zero events -- it would pass identically against a site with no maintenance
capability at all.

Skip instead of passing when the evidence list is empty. An empty list cannot
distinguish a working query API from one that returns nothing, and a provider
should not clear BFX02 without demonstrating the capability. A failed or
absent API still fails, so the stricter reading only affects the vacuous case.

Also stop counting InUse as repair history. _REPAIR_STATUSES is
{Maintenance, Reset, Error, Repairing}, but the filter admitted InUse too --
a normal lifecycle state -- so machines that had never been repaired produced
repair records.

Verified on a NICo dev site: BFX02-01 now skips (site has no maintenance
events), BFX02-03 still passes on genuine Error history across all 6 machines.

Signed-off-by: Alexandre Begnoche <abegnoche@nvidia.com>
@abegnoche abegnoche changed the title feat(remediation): BFX break-fix suite (M8) with NICo gaps documented feat(breakfix): BFX break-fix suite (BFX01-BFX06) with NICo coverage Aug 4, 2026
RetirementNoticesCheck kept the vacuous-pass pattern that BFX02-01 and BFX02-03
shed in 3c2df67: notices_queryable is set by the provider script whenever the
API call succeeds, so the check passed on an empty notice list. The my-isv demo
made this visible by passing with "0 notice(s) at site".

Skip on an empty list, matching the other two BFX02 checks. Give the my-isv stub
a sample notice so the demo still exercises the pass path.

Signed-off-by: Alexandre Begnoche <abegnoche@nvidia.com>
@abegnoche
abegnoche marked this pull request as ready for review August 5, 2026 20:03
@abegnoche
abegnoche requested a review from a team as a code owner August 5, 2026 20:03
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-08-05 20:04:41 UTC | Commit: b537792

@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: 8

🧹 Nitpick comments (8)
isvctl/configs/providers/nico/config/bare_metal.yaml (1)

565-571: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

machine_id and rack_id are declared but never passed to a step.

No step in this file consumes {{machine_id}} or {{rack_id}}. The mutating break-fix scripts accept only --org, --site-id, and --api-base. If these settings exist for the node and rack maintenance workflows, wire them into the matching step args. If they are placeholders for a later change, add a short comment stating that.

🤖 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 `@isvctl/configs/providers/nico/config/bare_metal.yaml` around lines 565 - 571,
Update the settings and related maintenance steps in the provider configuration
so machine_id and rack_id are either passed through their matching step args
using the existing template values, or marked with a brief comment as
intentional placeholders if no current step supports them. Ensure no declared
setting remains unused without that clarification.
isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py (2)

15-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Four break-fix stub scripts duplicate the same inline gap-reporting block. Each script repeats the same argparse setup, parse_known_args call, skip payload, and sys.exit(emit(...)) inside the module guard, with the names p, a, and r. Only the skip reason, gap ID, and operation keys differ. Add one shared helper in breakfix/_common.py that takes the reason, gap ID, and operation payload, then have each script call it from a typed main().

  • isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py#L15-L27: call the shared helper with gap BFX01-05 and {"requested": False, "node_removed_from_pool": False} from a main() -> int function.
  • isvctl/configs/providers/nico/scripts/breakfix/reset_gpus.py#L15-L27: call the shared helper with gap BFX01-01 and {"requested": False, "completed": False} from a main() -> int function.
  • isvctl/configs/providers/nico/scripts/breakfix/return_node_maintenance.py#L15-L27: call the shared helper with gap BFX01-02 and {"requested": False, "accepted": False} from a main() -> int function.
  • isvctl/configs/providers/nico/scripts/breakfix/return_rack_maintenance.py#L15-L27: call the shared helper with gap BFX01-03 and {"requested": False, "accepted": False} from a main() -> int function.
🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py`
around lines 15 - 27, Replace the duplicated module-guard logic with a shared
typed helper in isvctl/configs/providers/nico/scripts/breakfix/_common.py that
accepts the skip reason, gap ID, and operation payload, parses the existing
--org, --site-id, and --api-base arguments, emits the skip result, and returns
an exit code. In
isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py#L15-L27,
call it from main() -> int with gap BFX01-05 and operation {"requested": False,
"node_removed_from_pool": False}; apply the same main() structure in
reset_gpus.py#L15-L27 with BFX01-01 and {"requested": False, "completed":
False}, return_node_maintenance.py#L15-L27 with BFX01-02 and {"requested":
False, "accepted": False}, and return_rack_maintenance.py#L15-L27 with BFX01-03
and {"requested": False, "accepted": False}.

15-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the stub logic into a typed main() function.

query_bmc_kernel_logs.py in the same directory defines def main() -> int: and calls sys.exit(main()). This script puts all logic in the module guard and uses the names p, a, and r. The same shape repeats in the other break-fix stub scripts. Align the stubs with the main() convention and use descriptive names.

🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py`
around lines 15 - 27, Move the argument parsing and stub-result construction
from the __main__ guard into a typed main() -> int function, then invoke it with
sys.exit(main()). Within main(), replace the abbreviated p, a, and r variables
with descriptive names while preserving the existing required arguments,
skip_result call, operation payload, and emitted exit status.
isvctl/configs/providers/nico/scripts/breakfix/query_bmc_kernel_logs.py (1)

23-23: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

The generic "log" keyword makes the signal test broad.

_LOG_KEYWORDS contains "log", so any BMC probe whose text mentions logging counts as a kernel-log entry. entry_count then reports matched probes, not log entries. Consider dropping "log" or renaming the reported field to matched_probe_count so BmcKernelLogCheck evidence stays accurate.

🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/query_bmc_kernel_logs.py` at
line 23, Remove the generic "log" token from _LOG_KEYWORDS so BmcKernelLogCheck
only matches specific kernel-log indicators and entry_count continues to
represent log entries rather than broad probe matches.
isvctl/configs/providers/nico/scripts/breakfix/reset_gpus.py (1)

15-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Same stub shape as the other break-fix stubs.

Move the logic into a typed main() function and use descriptive variable names, to match query_bmc_kernel_logs.py.

🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/reset_gpus.py` around lines 15
- 27, Refactor the __main__ block into a typed main() function, matching the
structure used by query_bmc_kernel_logs.py. Replace abbreviated variables such
as p, a, and r with descriptive names, preserve the existing argument parsing,
skip_result call, operation payload, and emitted exit status, and invoke main()
from the __main__ guard.
isvctl/configs/providers/nico/scripts/breakfix/_common.py (1)

59-73: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add docstrings to emit, machine_labels, and history_entries.

The coding guidelines require a docstring on every function. list_site_machines and skip_result have one; these three do not.

♻️ Proposed docstrings
 def emit(result: dict[str, Any]) -> int:
+    """Print the result as JSON and return the process exit code."""
     print(json.dumps(result, indent=2))
     return 0 if result.get("success") else 1
 
 
 def machine_labels(machine: dict[str, Any]) -> dict[str, str]:
+    """Return the machine labels as a string-to-string mapping, dropping null values."""
     labels = machine.get("labels") or {}
     if not isinstance(labels, dict):
         return {}
     return {str(k): str(v) for k, v in labels.items() if v is not None}
 
 
 def history_entries(machine: dict[str, Any]) -> list[dict[str, Any]]:
+    """Return the machine status-history entries that are dict objects."""
     history = machine.get("statusHistory") or []
     return [entry for entry in history if isinstance(entry, dict)]

As per coding guidelines: "Every function and class must have docstrings following PEP 257".

🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/_common.py` around lines 59 -
73, Add concise PEP 257-compliant docstrings to the emit, machine_labels, and
history_entries functions, documenting each function’s purpose and return value
while preserving their existing behavior and logic.

Source: Coding guidelines

isvctl/configs/providers/nico/scripts/breakfix/return_node_maintenance.py (1)

15-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Same stub shape as the other break-fix stubs.

Move the logic into a typed main() function and use descriptive variable names, to match query_bmc_kernel_logs.py.

🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/return_node_maintenance.py`
around lines 15 - 27, Refactor the module-level CLI logic in the __main__ block
into a typed main() function, using descriptive names instead of p, a, and r
while preserving the existing arguments, skip_result call, operation payload,
and emitted exit status. Update the entry point to invoke main(), matching the
structure used by query_bmc_kernel_logs.py.
isvctl/configs/providers/nico/scripts/breakfix/return_rack_maintenance.py (1)

15-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Same stub shape as the other break-fix stubs.

Move the logic into a typed main() function and use descriptive variable names, to match query_bmc_kernel_logs.py.

🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/return_rack_maintenance.py`
around lines 15 - 27, Refactor the __main__ block into a typed main() function,
moving argument parsing and result construction into it. Replace abbreviated
variables such as p, a, and r with descriptive names, matching the structure and
naming style used by query_bmc_kernel_logs.py, while preserving the existing
arguments, skip_result call, operation values, and exit behavior.
🤖 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 `@isvctl/configs/providers/my-isv/scripts/breakfix/_stub.py`:
- Around line 21-30: Add concise PEP 257 docstrings to the new functions:
document the return contract of base_result and demo_or_not_implemented in
isvctl/configs/providers/my-isv/scripts/breakfix/_stub.py (lines 21-30), and
document the behavior of each main function in cordon_node.py (17-33),
query_bmc_kernel_logs.py (17-29), query_failure_notifications.py (17-30),
query_maintenance_events.py (17-39), query_planned_notifications.py (17-30),
query_repair_history.py (17-42), query_retirement_notices.py (17-38), and
query_serial_numbers.py (17-42). Ensure every function has a concise PEP
257-compliant docstring without changing its behavior.

In
`@isvctl/configs/providers/my-isv/scripts/breakfix/query_node_health_agents.py`:
- Around line 17-30: Add concise PEP 257-compliant docstrings immediately inside
each main function, describing its template operation:
query_node_health_agents.py (lines 17-30) for the node health-agent query,
query_switch_firmware.py (lines 17-29) for the switch-firmware query,
request_host_replacement.py (lines 17-35) for host replacement, reset_gpus.py
(lines 17-31) for GPU reset, return_node_maintenance.py (lines 17-36) for node
maintenance, and return_rack_maintenance.py (lines 17-31) for rack maintenance.
Preserve the existing argument parsing and result flow.

In `@isvctl/configs/providers/nico/scripts/breakfix/_common.py`:
- Around line 17-29: Update list_site_machines around the forge_get_all call to
catch the expected HTTP, URL, response-decoding, and JSON exceptions in addition
to NicoAuthError. For each handled failure, set result["error"] to the exception
text and return [], result so emit() always receives structured JSON.

In `@isvctl/configs/providers/nico/scripts/breakfix/query_maintenance_events.py`:
- Around line 24-32: Add concise PEP 257-compliant docstrings to every specified
new function: `_opened_at` and `main` in
`isvctl/configs/providers/nico/scripts/breakfix/query_maintenance_events.py`,
`_repair_entries` and `main` in
`isvctl/configs/providers/nico/scripts/breakfix/query_repair_history.py`, `main`
in `isvctl/configs/providers/nico/scripts/breakfix/query_retirement_notices.py`,
and `main` in
`isvctl/configs/providers/nico/scripts/breakfix/query_switch_firmware.py`;
preserve each function’s existing behavior.

In `@isvtest/src/isvtest/validations/breakfix.py`:
- Around line 33-38: Add concise PEP 257-compliant docstrings to every function
and class in the file, including _record_label, _maybe_skip, and each run
method. Ensure each docstring briefly describes the symbol’s purpose, while
preserving all existing behavior.
- Around line 330-336: Update the health-agent validation around the agents list
and not_running check so an empty agents result is treated as failure when
agents_observable is true. Report that no health-agent records were found, while
preserving the existing failure for non-running records and success behavior
when at least one agent is running.
- Around line 285-288: Update the existing-workload validation in the
surrounding BFX01-04 flow to require an exact True value for
operation.get("existing_workloads_running"). Treat missing, false, or any
non-boolean value as failure via set_failed, and only call set_passed when the
value is exactly True.

In `@isvtest/tests/test_breakfix.py`:
- Around line 10-17: Update the validation imports and tests in test_breakfix.py
to include PlannedMaintenanceNotificationCheck. Change
test_planned_notification_passes to instantiate the planned-maintenance check,
and retain a separate test that instantiates FailureNotificationCheck so both
validations are covered.

---

Nitpick comments:
In `@isvctl/configs/providers/nico/config/bare_metal.yaml`:
- Around line 565-571: Update the settings and related maintenance steps in the
provider configuration so machine_id and rack_id are either passed through their
matching step args using the existing template values, or marked with a brief
comment as intentional placeholders if no current step supports them. Ensure no
declared setting remains unused without that clarification.

In `@isvctl/configs/providers/nico/scripts/breakfix/_common.py`:
- Around line 59-73: Add concise PEP 257-compliant docstrings to the emit,
machine_labels, and history_entries functions, documenting each function’s
purpose and return value while preserving their existing behavior and logic.

In `@isvctl/configs/providers/nico/scripts/breakfix/query_bmc_kernel_logs.py`:
- Line 23: Remove the generic "log" token from _LOG_KEYWORDS so
BmcKernelLogCheck only matches specific kernel-log indicators and entry_count
continues to represent log entries rather than broad probe matches.

In `@isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py`:
- Around line 15-27: Replace the duplicated module-guard logic with a shared
typed helper in isvctl/configs/providers/nico/scripts/breakfix/_common.py that
accepts the skip reason, gap ID, and operation payload, parses the existing
--org, --site-id, and --api-base arguments, emits the skip result, and returns
an exit code. In
isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py#L15-L27,
call it from main() -> int with gap BFX01-05 and operation {"requested": False,
"node_removed_from_pool": False}; apply the same main() structure in
reset_gpus.py#L15-L27 with BFX01-01 and {"requested": False, "completed":
False}, return_node_maintenance.py#L15-L27 with BFX01-02 and {"requested":
False, "accepted": False}, and return_rack_maintenance.py#L15-L27 with BFX01-03
and {"requested": False, "accepted": False}.
- Around line 15-27: Move the argument parsing and stub-result construction from
the __main__ guard into a typed main() -> int function, then invoke it with
sys.exit(main()). Within main(), replace the abbreviated p, a, and r variables
with descriptive names while preserving the existing required arguments,
skip_result call, operation payload, and emitted exit status.

In `@isvctl/configs/providers/nico/scripts/breakfix/reset_gpus.py`:
- Around line 15-27: Refactor the __main__ block into a typed main() function,
matching the structure used by query_bmc_kernel_logs.py. Replace abbreviated
variables such as p, a, and r with descriptive names, preserve the existing
argument parsing, skip_result call, operation payload, and emitted exit status,
and invoke main() from the __main__ guard.

In `@isvctl/configs/providers/nico/scripts/breakfix/return_node_maintenance.py`:
- Around line 15-27: Refactor the module-level CLI logic in the __main__ block
into a typed main() function, using descriptive names instead of p, a, and r
while preserving the existing arguments, skip_result call, operation payload,
and emitted exit status. Update the entry point to invoke main(), matching the
structure used by query_bmc_kernel_logs.py.

In `@isvctl/configs/providers/nico/scripts/breakfix/return_rack_maintenance.py`:
- Around line 15-27: Refactor the __main__ block into a typed main() function,
moving argument parsing and result construction into it. Replace abbreviated
variables such as p, a, and r with descriptive names, matching the structure and
naming style used by query_bmc_kernel_logs.py, while preserving the existing
arguments, skip_result call, operation values, and exit behavior.
🪄 Autofix

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: 802eaa2e-d6ae-47d0-bea7-ce76f3e17235

📥 Commits

Reviewing files that changed from the base of the PR and between 6634373 and b537792.

📒 Files selected for processing (38)
  • docs/test-plan.yaml
  • isvctl/configs/providers/my-isv/config/bare_metal.yaml
  • isvctl/configs/providers/my-isv/config/k8s.yaml
  • isvctl/configs/providers/my-isv/scripts/breakfix/_stub.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/cordon_node.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_bmc_kernel_logs.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_failure_notifications.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_maintenance_events.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_node_health_agents.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_planned_notifications.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_repair_history.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_retirement_notices.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_serial_numbers.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_switch_firmware.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/request_host_replacement.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/reset_gpus.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/return_node_maintenance.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/return_rack_maintenance.py
  • isvctl/configs/providers/nico/config/bare_metal.yaml
  • isvctl/configs/providers/nico/config/key_access.yaml
  • isvctl/configs/providers/nico/scripts/breakfix/_common.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_bmc_kernel_logs.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_failure_notifications.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_maintenance_events.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_node_health_agents.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_planned_notifications.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_repair_history.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_retirement_notices.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_switch_firmware.py
  • isvctl/configs/providers/nico/scripts/breakfix/request_host_replacement.py
  • isvctl/configs/providers/nico/scripts/breakfix/reset_gpus.py
  • isvctl/configs/providers/nico/scripts/breakfix/return_node_maintenance.py
  • isvctl/configs/providers/nico/scripts/breakfix/return_rack_maintenance.py
  • isvctl/configs/suites/README.md
  • isvctl/configs/suites/bare_metal.yaml
  • isvctl/configs/suites/k8s.yaml
  • isvtest/src/isvtest/validations/breakfix.py
  • isvtest/tests/test_breakfix.py
💤 Files with no reviewable changes (1)
  • isvctl/configs/providers/nico/config/key_access.yaml

Comment thread isvctl/configs/providers/my-isv/scripts/breakfix/_stub.py
Comment thread isvctl/configs/providers/nico/scripts/breakfix/_common.py
Comment thread isvtest/src/isvtest/validations/breakfix.py
Comment thread isvtest/src/isvtest/validations/breakfix.py Outdated
Comment thread isvtest/src/isvtest/validations/breakfix.py
Comment thread isvtest/tests/test_breakfix.py
Correctness:
- CordonNodeCheck passed when `existing_workloads_running` was absent, since the
  guard only rejected an explicit False. BFX01-04 needs positive evidence that
  existing workloads kept running, so require exactly True.
- NodeHealthAgentCheck passed with "0 node(s)" when `agents` was empty. BFX04-01
  asks whether GPUd/Sentinel is running; no agent records means none is.
- `list_site_machines` caught only NicoAuthError, so an HTTPError or a decoding
  failure from `forge_get_all` escaped and killed the script before `emit()`,
  leaving the orchestrator with no JSON at all. Catch URLError and ValueError
  (covering HTTPError and JSONDecodeError) and return a structured failure.

Tests:
- `test_planned_notification_passes` instantiated FailureNotificationCheck, so
  PlannedMaintenanceNotificationCheck had no coverage. Test both, and add cases
  for the two correctness fixes above.

Docstrings: add the PEP 257 docstrings required by python-standards.mdc to the
break-fix validations and the my-isv/NICo provider scripts.

Signed-off-by: Alexandre Begnoche <abegnoche@nvidia.com>

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

🧹 Nitpick comments (1)
isvctl/configs/providers/nico/scripts/breakfix/_common.py (1)

32-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Correct the stale exception-handling comment.

The except (URLError, ValueError) block converts these failures into a structured result. The preceding comment says that the failures escape and produce no JSON. Replace it with wording that describes the current handled path.

🤖 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 `@isvctl/configs/providers/nico/scripts/breakfix/_common.py` around lines 32 -
34, Update the stale comment immediately before the except (URLError,
ValueError) block to state that these errors are caught and converted into a
structured failure result, preserving the existing exception-handling behavior.
🤖 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.

Nitpick comments:
In `@isvctl/configs/providers/nico/scripts/breakfix/_common.py`:
- Around line 32-34: Update the stale comment immediately before the except
(URLError, ValueError) block to state that these errors are caught and converted
into a structured failure result, preserving the existing exception-handling
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 12913a45-cf7d-4776-a6e1-2cdc24e60bb7

📥 Commits

Reviewing files that changed from the base of the PR and between b537792 and 2587d53.

📒 Files selected for processing (23)
  • isvctl/configs/providers/my-isv/scripts/breakfix/_stub.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/cordon_node.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_bmc_kernel_logs.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_failure_notifications.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_maintenance_events.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_node_health_agents.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_planned_notifications.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_repair_history.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_retirement_notices.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_serial_numbers.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_switch_firmware.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/request_host_replacement.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/reset_gpus.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/return_node_maintenance.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/return_rack_maintenance.py
  • isvctl/configs/providers/nico/scripts/breakfix/_common.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_bmc_kernel_logs.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_maintenance_events.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_repair_history.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_retirement_notices.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_switch_firmware.py
  • isvtest/src/isvtest/validations/breakfix.py
  • isvtest/tests/test_breakfix.py
🚧 Files skipped from review as they are similar to previous changes (18)
  • isvctl/configs/providers/nico/scripts/breakfix/query_maintenance_events.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_retirement_notices.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/cordon_node.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_switch_firmware.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_bmc_kernel_logs.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_failure_notifications.py
  • isvctl/configs/providers/nico/scripts/breakfix/query_repair_history.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_serial_numbers.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/reset_gpus.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_maintenance_events.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/_stub.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_bmc_kernel_logs.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/return_node_maintenance.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_switch_firmware.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/request_host_replacement.py
  • isvtest/tests/test_breakfix.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/return_rack_maintenance.py
  • isvctl/configs/providers/my-isv/scripts/breakfix/query_retirement_notices.py

Docstring coverage across the PR's Python files was 78%, below the 80%
threshold. The remaining gaps were all in test_breakfix.py: 7 test classes and
8 test methods. Every changed Python file is now at 100%.

Signed-off-by: Alexandre Begnoche <abegnoche@nvidia.com>
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.

BFX02-03: Query historical repair status for a node BFX02-01: Query upcoming/current maintenance events for a node

2 participants