Rust QC
Esta habilidad establece un estándar para el código Rust y lo aplica en tres modos. Las reglas provienen de la Rust Style Guide, las Rust API Guidelines, las Microsoft Pragmatic Rust Guidelines (2026.6), la Google Rust Style Guide, y las prácticas visibles en memchr, jiff, ripgrep, fd y dua-cli. Cuando esas fuentes discrepan, references/precedence.md registra la decisión para que nunca tengas que volver a litigarla.
Paso 1: Establecer contexto (todos los modos)
Haz esto antes de escribir o juzgar cualquier código. Detente e informa si falla una precondición; no adivines alrededor de un toolchain faltante o un manifest faltante.
- Encuentra la raíz del crate (el
Cargo.tomlmás cercano). Señala si es un workspace, una biblioteca, un binario o ambos, y si está publicado (publish = falseo consumido solo dentro del workspace o a través de FFI significa interno). - Lee primero las reglas propias del proyecto, porque anulan los valores predeterminados de esta habilidad:
rustfmt.tomlo.rustfmt.toml,clippy.toml,[lints]y[workspace.lints]enCargo.toml,edition,rust-version(MSRV),rust-toolchain.toml,CONTRIBUTING.md,AGENTS.mdoCLAUDE.md, y cualquierAI_POLICY.md. SiAI_POLICY.mdoCONTRIBUTING.mdrestringe contribuciones de IA o agentes, informa al usuario antes de producir cambios destinados a ese repositorio. - Clasifica el código como biblioteca o aplicación. Las reglas de diseño de API son vinculantes para bibliotecas y fuertes recomendaciones para aplicaciones, que deben favorecer la inmediatez sobre la generalidad.
- Señala las plataformas. Si
rust-toolchain.tomlenumera objetivos o el código tiene muchas puertas estilo#[cfg(windows)]para una plataforma diferente de este host, ejecuta la puerta con--target <triple>también (lint y documenta para ese objetivo; las pruebas se saltan). Advertencias como código muerto que aparecen solo en el host debido a puertas de plataforma son artefactos del host, no hallazgos. - Ejecuta
scripts/check.sh <crate-root>una vez para registrar la línea base. La necesitas para distinguir tus propias regresiones de deuda preexistente. Usa--features "<lista>"en lugar de--all-featurespredeterminado cuando el crate tenga características mutuamente excluyentes.
No instales toolchains, componentes o herramientas (nightly, Miri, cargo-hack) y no uses la red más allá de obtener crates a menos que el usuario lo solicite. Cuando una verificación necesite algo que falte, dilo y recomiéndalo.
Paso 2: Elegir el modo
Crear cuando el usuario quiera nuevas funciones, métodos, tipos, módulos o crates. Sigue "Crear código" a continuación.
Modificar cuando el usuario quiera cambiar código existente: una característica, refinamiento, corrección de errores, refactorización o remediación de hallazgos de auditoría. Sigue "Modificar código" a continuación.
Auditar cuando el usuario quiera que se revise, evalúe o verifique código existente, con problemas identificados y arreglos propuestos. Sigue "Auditar código" a continuación. Auditar no cambia el código a menos que el usuario lo solicite; produce hallazgos.
Una solicitud puede abarcar múltiples modos ("audita este módulo y arregla lo que encuentres"). Ejecuta la auditoría primero, informa, luego cambia a modificar para los arreglos.
Reglas no negociables
Estas se aplican en cada modo. El conjunto completo de reglas, con IDs, vive en los archivos de referencia enumerados al final.
- El formateo es trabajo de rustfmt. Nunca formatee a mano contra rustfmt. Nunca agregue
#[rustfmt::skip]excepto para alineación deliberada (tablas, matrices) o código generado. - El código es sólido. El código seguro no debe poder causar comportamiento indefinido. Cada bloque
unsafetiene un comentario// SAFETY:directamente encima explicando por qué se cumple cada precondición. Cadaunsafe fnyunsafe traittiene una sección de documentación# Safety. Usaunsafesolo para FFI, una necesidad de rendimiento comparada, o una abstracción novedosa, y nunca para eludirSend,Synco los lifetimes. Verreferences/unsafe.md. - Errores versus pánicos. Fallos recuperables causados por la entrada o el entorno devuelven
Result(oOptioncuando la causa es obvia). Los errores de programación detectados provocan pánico. El código de biblioteca nunca entra en pánico por entrada del llamante que podría ser razonablemente inválida. Verreferences/errors.md. - Errores de biblioteca permiten que los llamantes ramifiquen sin analizar texto. Un tipo de error concreto con un
kind()que devuelve un enum#[non_exhaustive]público, o predicadosis_*(). Los campos privados están bien; un kind privado sin acceso es un defecto. Los mensajes apuntan al token ofensivo y la posición, y nunca copian toda la entrada. - Sin
unwrap()desnudo en código de producción. Usa?, coincidencia de patrones, oexpect("...")cuyo mensaje establece por qué se cumple la invariante.unwrap()está bien en pruebas. Los ejemplos de documentación usan?con la línea oculta# Ok::<(), Box<dyn std::error::Error>>(()). - Cada nueva dependencia es un costo, las dev-dependencies incluidas. Añade una solo cuando elimine complejidad real o proporcione corrección que no puedas escribir razonablemente (el plegado de mayúsculas y minúsculas Unicode es una buena razón; un framework de pruebas de propiedades para un parser de 100 líneas no). Di por qué en tu informe.
- La estructura coincide con el tamaño. No crees un módulo para una función pequeña y su tipo de error; un módulo se gana su archivo con un concepto distinto y varios elementos o unos cientos de líneas.
- Las anulaciones de lint usan
#[expect(lint, reason = "...")], no#[allow], para que surjan anulaciones obsoletas. - Los elementos públicos están documentados , la primera oración es una línea de unas 15 palabras, y las funciones incluyen secciones
# Errors,# Panics, y# Safetysiempre que apliquen. Verreferences/documentation.md. - Los tipos públicos implementan
Debug. Los tipos destinados a ser leídos por personas también implementanDisplay. - Los comentarios explican por qué, no qué. Si un comentario repite el código, elimínalo. El comentario del asignador de memoria de ripgrep en
crates/core/main.rses el modelo: decisión, razón y las condiciones bajo las que aplica. - Sin diagramas ASCII-art o caracteres de dibujo de cajas en comentarios o documentación. Describe la estructura en oraciones; los dibujos son ilegibles con un lector de pantalla y se pudren cuando el código cambia. (Convención del equipo, no ascendente).
- Sin contenido de diario de diseño en la documentación. La documentación describe el comportamiento actual, no cómo llegó a ser el código o qué pautas se siguieron.
- Las pruebas verifican el comportamiento. Sin pruebas que repitan una constante o reflejen las ramas de la implementación.
Crear código
Trabaja de afuera hacia adentro: tipos y firmas primero, luego documentación, luego implementación, luego pruebas. Escribir el comentario de documentación antes del cuerpo es la forma más rápida de descubrir una API confusa.
- Ubícalo. Coloca el elemento en el módulo que posee su concepto; en un crate pequeño eso suele ser
lib.rs. Los nuevos módulos se nombran según su tipo principal y solo se crean cuando el código lo justifica (ORG-19). Verreferences/organization.md. - Modela con tipos. Newtypes para valores que son fáciles de confundir o que llevan invariantes, con constructores que hacen cumplir la invariante. Un
enumen lugar de un parámetroboolcuyo significado no es obvio en el lugar de la llamada. Campos nombrados sobre tuplas. Haz que los estados inválidos sean irrepresentables. - Dale forma a la firma. Toma prestado lo que solo lees (
&str,&[T],&Path,Option<&T>), toma propiedad solo cuando almacenas o consumes. En bibliotecas, aceptaimpl AsRef<Path>oimpl IntoIteratordonde elimine fricción; en aplicaciones, mantén tipos concretos. Builders para tipos con varias opciones opcionales, validando enbuild(). Verreferences/api-design.md. - Nómbralo. Mayúsculas y minúsculas según RFC 430; conversiones
as_/to_/into_; constructoresnew,with_*,try_new; gettersfoo(). Sin palabras comodín (Manager,Service,Factory,Helper,Util), y ningún nombre que colisione con un significado existente en la misma interfaz (NAME-9). - Documéntalo según
references/documentation.md, incluyendo un ejemplo ejecutable para elementos públicos, y la unidad de cualquier posición o longitud que devuelvas. - Impleméntalo. Funciones de un solo propósito. Un bucle
forsimple sobre una cadena de combinadores una vez que la cadena necesita condicionales o estado externo; combinadores cuando reemplacen lógica escrita a mano (any,position,sum). Anotaciones de tipo donde la inferencia dejaría a un lector adivinando. El texto humano obtiene manejo consciente de Unicode: la coincidencia que no distingue mayúsculas y minúsculas usa el plegado de mayúsculas y minúsculas Unicode, o documenta sus lagunas (API-27). - Maneja errores según
references/errors.md: en bibliotecas un tipo de error concreto con un kind público o predicados; en aplicacionesanyhowcon.context(). - Pruébalo según
references/testing.md: pruebas unitarias en línea, pruebas de integración bajotests/, y verificaciones amplias de invariantes que no necesiten nuevas dependencias (enumera entradas cortas, o un bucle con semilla contra una referencia ingenua). - Verifica con la puerta a continuación.
Modificar código
El objetivo es el cambio correcto más pequeño que deje el código tocado al menos tan claro como lo encontraste.
- Lee antes de editar. Lee toda la función, sus llamantes, sus pruebas y la API vecina. Identifica convenciones locales (estilo de importación, tipo de error, estilo de encabezado de documentación como
# Exampleversus# Examples, ancho de línea, densidad, nombres de parámetros y claves) y adáptate a ellas, incluso si los valores predeterminados de esta habilidad difieren. - Las correcciones de errores comienzan con una prueba fallida que cubra la clase de error. Reproduce la entrada informada, luego agrega los casos vecinos que la misma causa raíz rompe (más elementos, otros ordenamientos, combinaciones). Míralos fallar, corrige la causa raíz, míralos pasar. Si el proyecto mantiene pruebas de regresión en un solo lugar (
tests/regression.rsde ripgrep), añade las tuyas allí. - Corrige la causa, no el síntoma. Un nuevo
unwrap_or_default(),clone(), o retorno temprano que silencie un fallo no es una corrección a menos que puedas explicar por qué la ruta original era incorrecta. Pon un comentario de una línea en la corrección si la razón no es obvia a partir del código. - Mantente quirúrgico. No renombres, reordenes ni reformatees código que no se te pidió tocar. Enumera problemas no relacionados para el usuario en lugar de corregirlos en silencio.
- Mantén las APIs y ABIs públicas estables a menos que el usuario apruebe un cambio disruptivo. Añadir un campo a una estructura pública con campos públicos, una variante a un enum público exhaustivo, un método de trait requerido, o cambiar un contrato FFI es disruptivo.
- Actualiza la documentación y las pruebas con el código. Una firma o comportamiento cambiado significa
# Errors,# Panics, ejemplos y pruebas actualizados en el mismo cambio. - Formateo: si la línea base estaba limpia de rustfmt, ejecuta
cargo fmt. Si no lo estaba, formatea solo lo que cambiaste e informa al usuario. Sirustfmt.tomlusa opciones solo de nightly (rustfmt estable advierte que están "solo disponibles en el canal nightly"), el estándar del proyecto escargo +nightly fmt; úsalo si está instalado, y de lo contrario no formatees nada automáticamente y dilo, porque rustfmt estable reescribiría el código contra la configuración del proyecto. - Remediación de una auditoría: corrige los hallazgos por orden de gravedad, un hallazgo por cambio lógico, y nombra el hallazgo en tu resumen.
- Verifica con la puerta a continuación y confirma que no introdujiste nuevas advertencias en relación con la línea base, en cada objetivo que verificaste en el paso 1.
Auditar código
-
Ejecuta
scripts/check.sh --audit <crate-root>(más--targetsegún el paso 1). El pase--auditinforma, con accesibilidad de API pública,unsafeno documentado, documentación faltante y secciones# Errors/# Panics,unwrapfuera de pruebas,#[allow]sin razón,dbg!/todo!, importaciones glob, y aserciones sin mensajes. Informa estos resultados de higiene de manera compacta: un hallazgo Minor por categoría (documentación,Debug, comentarios SAFETY, configuración de lint), cada uno con un conteo y los pocos casos que más importan. Un paso de puerta que falla solo porque el toolchain aquí es más nuevo que el que el CI del proyecto orust-toolchain.tomlusa es deriva del toolchain: un hallazgo Minor, no un Major. -
Ejecuta
python3 -I scripts/audit_scan.py <crate-root>para lo que clippy no puede ver: reexportaciones glob, nombres de tipo comodín, comentarios ASCII-art, documentación de historial de diseño, tablas de parámetros, TODOs desnudos, mensajesexpectvacíos, y macros de impresión en código de biblioteca. Confirma cada acierto leyendo el código; descarta falsos positivos. -
Sondea el comportamiento como lo encuentran los usuarios. Aquí es donde se encuentran la mayoría de los errores visibles para el usuario en crates reales, así que dedica la mayor parte de la auditoría aquí y en el paso 5. Lee la documentación, especificación y pruebas del crate para enumerar las características de entrada que afirma manejar. Para cada una, construye una entrada realista pequeña que las pruebas existentes no cubran, ejecútala a través de la API pública desde un crate desechable fuera del workspace, y compara la salida con lo que un usuario debería obtener. Cubre las características que el formato permite pero los fixtures omiten:
- valores heredados, indirectos o predeterminados
- duplicados
- partes opcionales u ocultas
- daño leve que otras herramientas toleran
- texto no ASCII y codificaciones heredadas
- tamaños grandes pero legítimos
Informa cada problema confirmado con la entrada que lo muestra.
-
Aprovecha la entrada no confiable. Para cada función pública que analice bytes o texto no confiables, aliméntala con cada entrada corta sobre un alfabeto relevante o unos pocos millones de mutaciones aleatorias con semilla, y detecta pánicos. También prueba estructuras elaboradas que hacen que el trabajo crezca más rápido que el tamaño de la entrada (referencias compartidas o recursivas, anidamiento profundo) bajo un tiempo de espera.
-
Lee el código para lo que las herramientas no pueden juzgar: solidez de cada bloque
unsafe, diseño de errores, forma de la API, límites de módulos, nomenclatura, calidad de las pruebas, y si los comentarios explican por qué. En código que se comunica con el sistema operativo, también verifica:- pánicos en una syscall, fallo de E/S o entorno (
assert!ounwrapen un valor de retorno, una variable de entorno no UTF-8 o campo passwd) - código entre
forkyexec(cierrespre_exec) o en un manejador de señal que asigna, bloquea, formatea, registra o sale, nada de lo cual es seguro para async-signal - descriptores de archivo o manejadores filtrados, y señales enviadas a un ID de proceso que puede haber sido recolectado y reutilizado
- conversiones de estrechamiento y aritmética no verificada en tamaños, conteos y coordenadas
Usa
references/audit-checklist.md. - pánicos en una syscall, fallo de E/S o entorno (
-
Informa usando el formato a continuación. Propón una corrección concreta para cada hallazgo.
Los pasos 1 y 2 son un piso rápido, no la auditoría: no dediques más de aproximadamente una quinta parte del tiempo en ellos. Una auditoría que enumere principalmente lint, documentación y s...