From ce88c3c6c0ce0bdb601864ea6f64941cacd6e84f Mon Sep 17 00:00:00 2001 From: Andrew Forgue Date: Mon, 13 Jul 2026 12:34:30 -0700 Subject: [PATCH 1/2] docs(agents,style): Update agent guidance Updates agent guidance to avoid free-standing functions where possible, and move the "stringly"-typed guidance to the general style guide since it's not just for agents. --- AGENTS.md | 24 +++++++---------- STYLE_GUIDE.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 4442e5f091..575a429316 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,10 +5,10 @@ This file provides guidance for AI coding agents working in the ## Project Overview -**NCX Infra Controller (NICo)** is an API-based microservice written in Rust -that provides site-local, zero-trust, bare-metal lifecycle management with -DPU-enforced isolation. It automates the complexity of the bare-metal lifecycle -to fast-track building next-generation AI Cloud offerings. +**NVIDIA Infra Controller (NICo)** is an API-based microservice written in Rust +and Golang that provides site-local, zero-trust, bare-metal lifecycle +management with DPU-enforced isolation. It automates the complexity of the +bare-metal lifecycle to fast-track building next-generation AI Cloud offerings. > **Status:** Experimental/Preview. APIs, configurations, and features may > change without notice between releases. @@ -45,6 +45,7 @@ infra-controller/ ├── lints/ # Custom Clippy lints (carbide-lints crate) ├── include/ # Shared Makefile fragments ├── .github/ # GitHub Actions workflows and templates +|-- rest-api/ # Golang-based REST API ├── Cargo.toml # Workspace dependency management ├── Makefile.toml # Primary build/task automation ├── Makefile-build.toml # Build-specific tasks @@ -53,6 +54,7 @@ infra-controller/ ## Technology Stack +### gRPC API and components: - **Language:** Rust (edition 2024, toolchain pinned in `rust-toolchain.toml`) - **Async runtime:** Tokio - **gRPC framework:** Tonic (with TLS via Rustls/aws_lc_rs) @@ -62,6 +64,9 @@ infra-controller/ - **Build tool:** `cargo-make` (TOML task runner) - **API definitions:** Protocol Buffers (protobuf) +### REST API and components +- **Language (REST API):** Golang 1.26.5 + ## Build, Test, and Lint Commands All task automation uses `cargo-make`. Install it with: @@ -159,17 +164,6 @@ verification expectations. See [`STYLE_GUIDE.md`](STYLE_GUIDE.md) for detailed Rust coding conventions. Make sure to review it to ensure changes meet the expected style of the codebase. -### Avoid stringly-typed values - -When a value has a known, finite set of possibilities, model it with an enum (or -a struct of enums) and derive its string form via `Display`/`FromStr` — do not -pass it around as a bare `String` or `&str` literal. Stringly-typed values are -easy to misspell (`NICO-` vs `NICOO-`), silently break log filters and alerts, -and can't be exhaustively checked by the compiler. See -[`ErrorCode`](crates/api-model/src/errors.rs) for the pattern: typed -`ErrorSystem`/`ErrorSubsystem` parts plus a `code`, rendered to the wire string -in one place. Reserve raw strings for genuinely open-ended values. - ### Instrumentation: logs and metrics The decision rule: diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md index 18bff70019..7c8bb09bb6 100644 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -695,3 +695,74 @@ fn prefer() { fails().ok(); } ``` + +### Avoid stringly-typed values + +When a value has a known, finite set of possibilities, model it with an enum (or +a struct of enums) and derive its string form via `Display`/`FromStr` — do not +pass it around as a bare `String` or `&str` literal. Stringly-typed values are +easy to misspell (`NICO-` vs `NICOO-`), silently break log filters and alerts, +and can't be exhaustively checked by the compiler. See +[`ErrorCode`](crates/api-model/src/errors.rs) for the pattern: typed +`ErrorSystem`/`ErrorSubsystem` parts plus a `code`, rendered to the wire string +in one place. Reserve raw strings for genuinely open-ended values. + +### Prefer methods over free functions + +When a function operates primarily on a specific type, define it as a method on that type rather than a free-standing function. This keeps related behavior co-located with the type, makes it easier to discover via autocomplete, and reads more naturally at the call site. + +```rust +// Avoid — free function that operates on a specific type +fn machine_display_name(machine: &Machine) -> String { + format!("{} ({})", machine.hostname, machine.id) +} + +fn is_machine_ready(machine: &Machine) -> bool { + machine.state == MachineState::Ready && machine.health.is_ok() +} + +// Prefer — methods on the type itself +impl Machine { + fn display_name(&self) -> String { + format!("{} ({})", self.hostname, self.id) + } + + fn is_ready(&self) -> bool { + self.state == MachineState::Ready && self.health.is_ok() + } +} +``` + +This applies to enums as well: + +```rust +// Avoid +fn is_terminal_state(state: &MachineState) -> bool { + matches!(state, MachineState::Failed | MachineState::Decommissioned) +} + +fn state_label(state: &MachineState) -> &'static str { + match state { + MachineState::Ready => "ready", + MachineState::Failed => "failed", + MachineState::Decommissioned => "decommissioned", + } +} + +// Prefer +impl MachineState { + fn is_terminal(&self) -> bool { + matches!(self, Self::Failed | Self::Decommissioned) + } + + fn label(&self) -> &'static str { + match self { + Self::Ready => "ready", + Self::Failed => "failed", + Self::Decommissioned => "decommissioned", + } + } +} +``` + +Free functions are still appropriate when the logic genuinely spans multiple unrelated types, belongs in a module rather than a single type, or is a utility with no natural owner. From a3c12bef20c0d4592050b2ae3bdabd996fe76173 Mon Sep 17 00:00:00 2001 From: Andrew Forgue Date: Mon, 13 Jul 2026 12:51:15 -0700 Subject: [PATCH 2/2] CR fixes --- AGENTS.md | 4 ++-- STYLE_GUIDE.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 575a429316..889259630d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,7 +45,7 @@ infra-controller/ ├── lints/ # Custom Clippy lints (carbide-lints crate) ├── include/ # Shared Makefile fragments ├── .github/ # GitHub Actions workflows and templates -|-- rest-api/ # Golang-based REST API +├── rest-api/ # Golang-based REST API ├── Cargo.toml # Workspace dependency management ├── Makefile.toml # Primary build/task automation ├── Makefile-build.toml # Build-specific tasks @@ -65,7 +65,7 @@ infra-controller/ - **API definitions:** Protocol Buffers (protobuf) ### REST API and components -- **Language (REST API):** Golang 1.26.5 +- **Language (REST API):** Golang 1.26.x ## Build, Test, and Lint Commands diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md index 7c8bb09bb6..d216af2c52 100644 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -698,8 +698,8 @@ fn prefer() { ### Avoid stringly-typed values -When a value has a known, finite set of possibilities, model it with an enum (or -a struct of enums) and derive its string form via `Display`/`FromStr` — do not +When a value has a known, finite set of possibilities, model it with an enum +(or a struct of enums) and implement traits `Display` and `FromStr` — do not pass it around as a bare `String` or `&str` literal. Stringly-typed values are easy to misspell (`NICO-` vs `NICOO-`), silently break log filters and alerts, and can't be exhaustively checked by the compiler. See