@mrciphersmith/keryx 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/dist/cli.js +3099 -1160
- package/dist/core.js +22 -3
- package/docs/README.md +2 -0
- package/package.json +1 -1
- package/src/gdskills/bundled/install-manifest.json +319 -76
- package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.md +19 -26
- package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +6 -6
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +4 -7
- package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +2 -4
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +23 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +17 -17
- package/src/gdskills/bundled/stacks/django/agent-refs.json +3 -0
- package/src/gdskills/bundled/stacks/django/governance/eval.json +1763 -0
- package/src/gdskills/bundled/stacks/django/governance/scout.json +40 -0
- package/src/gdskills/bundled/stacks/django/pack.json +43 -0
- package/src/gdskills/bundled/stacks/django/rules/coding-style.mdc +80 -0
- package/src/gdskills/bundled/stacks/django/rules/patterns.mdc +92 -0
- package/src/gdskills/bundled/stacks/django/rules/security.mdc +92 -0
- package/src/gdskills/bundled/stacks/django/rules/testing.mdc +89 -0
- package/src/gdskills/bundled/stacks/django/skills/django-build-fix/SKILL.md +149 -0
- package/src/gdskills/bundled/stacks/django/skills/django-build-fix/evals.json +49 -0
- package/src/gdskills/bundled/stacks/django/skills/django-code-review/SKILL.md +137 -0
- package/src/gdskills/bundled/stacks/django/skills/django-code-review/evals.json +48 -0
- package/src/gdskills/bundled/stacks/django/skills/django-implementation/SKILL.md +147 -0
- package/src/gdskills/bundled/stacks/django/skills/django-implementation/evals.json +75 -0
- package/src/gdskills/bundled/stacks/django/skills/django-migrate/SKILL.md +166 -0
- package/src/gdskills/bundled/stacks/django/skills/django-migrate/evals.json +49 -0
- package/src/gdskills/bundled/stacks/django/skills/django-testing/SKILL.md +130 -0
- package/src/gdskills/bundled/stacks/django/skills/django-testing/evals.json +48 -0
- package/src/gdskills/bundled/stacks/fastapi/agent-refs.json +3 -0
- package/src/gdskills/bundled/stacks/fastapi/governance/eval.json +1777 -0
- package/src/gdskills/bundled/stacks/fastapi/governance/scout.json +34 -0
- package/src/gdskills/bundled/stacks/fastapi/pack.json +43 -0
- package/src/gdskills/bundled/stacks/fastapi/rules/coding-style.mdc +68 -0
- package/src/gdskills/bundled/stacks/fastapi/rules/patterns.mdc +108 -0
- package/src/gdskills/bundled/stacks/fastapi/rules/security.mdc +99 -0
- package/src/gdskills/bundled/stacks/fastapi/rules/testing.mdc +85 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-build-fix/SKILL.md +157 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-build-fix/evals.json +76 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-code-review/SKILL.md +150 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-code-review/evals.json +74 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-implementation/SKILL.md +158 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-implementation/evals.json +75 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-testing/SKILL.md +146 -0
- package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-testing/evals.json +74 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/agent-refs.json +3 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/governance/eval.json +2194 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/governance/scout.json +39 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/pack.json +40 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/coding-style.mdc +67 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/patterns.mdc +65 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/security.mdc +69 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/testing.mdc +80 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-build-fix/SKILL.md +144 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-build-fix/evals.json +74 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-code-review/SKILL.md +129 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-code-review/evals.json +74 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-implementation/SKILL.md +147 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-implementation/evals.json +75 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-migrate/SKILL.md +139 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-migrate/evals.json +74 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-testing/SKILL.md +128 -0
- package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-testing/evals.json +73 -0
- package/src/gdskills/bundled/stacks/python/agent-refs.json +2 -1
- package/src/gdskills/bundled/stacks/python/pack.json +1 -1
- package/src/gdskills/bundled/stacks/rust/agent-refs.json +3 -0
- package/src/gdskills/bundled/stacks/rust/governance/eval.json +1823 -0
- package/src/gdskills/bundled/stacks/rust/governance/scout.json +32 -0
- package/src/gdskills/bundled/stacks/rust/pack.json +42 -0
- package/src/gdskills/bundled/stacks/rust/rules/coding-style.mdc +93 -0
- package/src/gdskills/bundled/stacks/rust/rules/patterns.mdc +85 -0
- package/src/gdskills/bundled/stacks/rust/rules/security.mdc +85 -0
- package/src/gdskills/bundled/stacks/rust/rules/testing.mdc +82 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-build-fix/SKILL.md +141 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-build-fix/evals.json +78 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-code-review/SKILL.md +127 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-code-review/evals.json +72 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-implementation/SKILL.md +133 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-implementation/evals.json +79 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-testing/SKILL.md +130 -0
- package/src/gdskills/bundled/stacks/rust/skills/rust-testing/evals.json +75 -0
- package/src/gdskills/bundled/agents/python-build-fixer.md +0 -52
- package/src/gdskills/bundled/agents/python-code-auditor.md +0 -49
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Use when cargo build/cargo clippy fails, or Cargo.toml/Cargo.lock are out of sync -- resolves dependency/edition/MSRV mismatches, borrow-checker and lifetime errors, trait-bound errors, clippy failures, and a failing cargo test, with the smallest root-cause fix.",
|
|
4
|
+
"decision": "fork",
|
|
5
|
+
"topMatch": "go/go-build-fix",
|
|
6
|
+
"recordedAt": "2026-09-25T18:06:22.209Z",
|
|
7
|
+
"skillName": "rust-build-fix",
|
|
8
|
+
"justification": "top match go/go-build-fix is the same build-fix category but for a different language's own toolchain (go build/vet vs. cargo build/clippy/borrow-checker errors), not a substitute; a Rust-scoped fork is warranted since Go's build-fix has no visibility into Rust's own trait-bound/borrow-checker/cargo failure modes."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Use when reviewing a Rust change for ownership, panic, and safety risks -- unwrap/expect on fallible input, unnecessary clone as a borrow-checker workaround, unjustified or oversized unsafe blocks, blocking calls in async fn, unchecked arithmetic/indexing on untrusted data, and error types that lose their source. Read-only, no edits.",
|
|
12
|
+
"decision": "create",
|
|
13
|
+
"topMatch": "angular/angular-code-review",
|
|
14
|
+
"recordedAt": "2026-09-25T18:06:22.532Z",
|
|
15
|
+
"skillName": "rust-code-review"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"query": "Use when implementing or extending a feature in a Rust crate -- Cargo.toml/edition/workspace layout, ownership and borrowing, Result/Option error handling with the ? operator, thiserror/anyhow conventions, trait and generic design, and avoiding blocking calls in async fn.",
|
|
19
|
+
"decision": "create",
|
|
20
|
+
"topMatch": "rust/rust-build-fix",
|
|
21
|
+
"recordedAt": "2026-09-25T18:06:22.848Z",
|
|
22
|
+
"skillName": "rust-implementation"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"query": "Use when a Rust crate's own test suite needs writing, extending, or fixing with cargo test -- #[cfg(test)] unit tests, tests/ integration tests, multi-case assertions built as a Vec of structs, #[tokio::test] async tests joined properly, proptest/quickcheck property-based checks on a Rust struct or enum, and criterion benchmarks.",
|
|
26
|
+
"decision": "create",
|
|
27
|
+
"topMatch": "rust/rust-implementation",
|
|
28
|
+
"recordedAt": "2026-09-25T18:06:23.160Z",
|
|
29
|
+
"skillName": "rust-testing",
|
|
30
|
+
"justification": "top match go/go-testing is the same test-authoring category but for a different language's own idiom (table-driven Go subtests vs. Rust's #[cfg(test)] modules, proptest, criterion benchmarks), not a substitute; a Rust-scoped fork is warranted since Go's testing skill has no Rust-specific guidance."
|
|
31
|
+
}
|
|
32
|
+
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "rust",
|
|
3
|
+
"family": "language",
|
|
4
|
+
"modules": ["rust-rules", "rust-skills"],
|
|
5
|
+
"detectionMarkers": ["rust"],
|
|
6
|
+
"provenance": {
|
|
7
|
+
"origin": "authored",
|
|
8
|
+
"sourceRef": "flow 335, Wave 4 batch 3"
|
|
9
|
+
},
|
|
10
|
+
"stability": "experimental",
|
|
11
|
+
"skills": {
|
|
12
|
+
"implement": ["rust-implementation"],
|
|
13
|
+
"test": ["rust-testing"],
|
|
14
|
+
"review": ["rust-code-review"],
|
|
15
|
+
"build-fix": ["rust-build-fix"],
|
|
16
|
+
"migrate": []
|
|
17
|
+
},
|
|
18
|
+
"agentProfile": {
|
|
19
|
+
"displayName": "Rust",
|
|
20
|
+
"auditFocus": [
|
|
21
|
+
"an .unwrap()/.expect() on a Result or Option built from untrusted or fallible external input (a network response, a file read, a parsed argument) instead of propagating with ?",
|
|
22
|
+
"an unsafe block with no # Safety doc comment stating the invariants the caller must uphold, or one wider than the specific operation that requires it",
|
|
23
|
+
"a borrow-checker conflict worked around with an unnecessary .clone() instead of restructuring ownership, splitting borrows, or using a reference",
|
|
24
|
+
"a blocking call (std::thread::sleep, a synchronous file/network read, a std::sync::Mutex held across an .await) inside an async fn instead of the async equivalent or spawn_blocking",
|
|
25
|
+
"an integer operation on untrusted input with no overflow/bounds check (raw arithmetic or indexing instead of checked_add/get/saturating_* where the value could be attacker-influenced)",
|
|
26
|
+
"a custom error type that loses the underlying cause instead of using #[source]/#[from] (thiserror) or .context() (anyhow) to preserve it"
|
|
27
|
+
],
|
|
28
|
+
"buildCommands": [
|
|
29
|
+
"cargo build --all-targets",
|
|
30
|
+
"cargo clippy --all-targets -- -D warnings",
|
|
31
|
+
"cargo fmt --check",
|
|
32
|
+
"cargo test"
|
|
33
|
+
],
|
|
34
|
+
"fixGuardrails": [
|
|
35
|
+
"Never silence a clippy finding with a blanket #[allow(clippy::all)] or a lint-level allow instead of fixing the root cause.",
|
|
36
|
+
"Never add .unwrap()/.expect() to make a type error or a Result mismatch disappear; propagate with ? or handle the error explicitly.",
|
|
37
|
+
"Never bump the edition or MSRV in Cargo.toml just to make an error disappear without understanding why it changed.",
|
|
38
|
+
"Never delete or skip a failing test to reach a green build.",
|
|
39
|
+
"Never widen an unsafe block or drop a # Safety comment to silence a compiler or clippy complaint about it."
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
extends: common
|
|
3
|
+
paths: ["**/*.rs"]
|
|
4
|
+
metadata:
|
|
5
|
+
origin: authored
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Rust coding style
|
|
9
|
+
|
|
10
|
+
Narrows `core-common-rules`' stack-agnostic style rules to modern Rust
|
|
11
|
+
(2021/2024 edition) idiom. Applies only to `*.rs` files — everything not
|
|
12
|
+
Rust-specific still comes from the common rules this file `extends`.
|
|
13
|
+
|
|
14
|
+
## Naming and structure
|
|
15
|
+
|
|
16
|
+
- `snake_case` for functions, methods, variables, and modules;
|
|
17
|
+
`UpperCamelCase` for types, traits, and enum variants; `SCREAMING_SNAKE_CASE`
|
|
18
|
+
for constants and statics — `rustfmt`/`rustc` will warn on a mismatch.
|
|
19
|
+
- A crate's public surface lives at the paths re-exported from `lib.rs`;
|
|
20
|
+
keep implementation details `pub(crate)` or private and re-export
|
|
21
|
+
deliberately, rather than making every module `pub` by default.
|
|
22
|
+
- An identifier's name shrinks with its scope: a short-lived closure
|
|
23
|
+
parameter can be `x`, a `pub` function gets a full descriptive name.
|
|
24
|
+
|
|
25
|
+
## Ownership, borrowing, and errors
|
|
26
|
+
|
|
27
|
+
- Prefer borrowing (`&T`/`&mut T`) over taking ownership when the callee
|
|
28
|
+
does not need to keep the value; prefer `&str`/`&[T]` parameters over
|
|
29
|
+
`&String`/`&Vec<T>` so callers can pass either owned or borrowed data.
|
|
30
|
+
- Resolve a borrow-checker conflict by restructuring ownership, splitting
|
|
31
|
+
the borrow, or shortening a borrow's lifetime — reach for `.clone()`
|
|
32
|
+
only when the value genuinely needs to be duplicated, and say why in a
|
|
33
|
+
comment when the clone is non-obvious; an unnecessary `.clone()` used
|
|
34
|
+
purely to silence the borrow checker is a cost paid on every call.
|
|
35
|
+
- `Result<T, E>` for anything that can fail; propagate with the `?`
|
|
36
|
+
operator rather than a manual `match` that just re-returns `Err`.
|
|
37
|
+
`Option<T>` for genuine absence, not as a substitute for `Result` on an
|
|
38
|
+
operation that can fail for a reason worth naming.
|
|
39
|
+
- Never call `.unwrap()`/`.expect()` on a `Result`/`Option` built from
|
|
40
|
+
fallible or untrusted input (a parsed argument, a network response, a
|
|
41
|
+
file read, a map lookup on external data) in production code without a
|
|
42
|
+
stated invariant that makes it truly infallible; prefer `?`, a `match`,
|
|
43
|
+
or a combinator (`unwrap_or`, `unwrap_or_else`, `ok_or`) that handles the
|
|
44
|
+
failure path.
|
|
45
|
+
- Use `thiserror` to derive `std::error::Error` for a library's own error
|
|
46
|
+
enum (`#[error("...")]` per variant, `#[source]`/`#[from]` to preserve
|
|
47
|
+
the underlying cause); use `anyhow::Result`/`.context()`/`.with_context()`
|
|
48
|
+
in application/binary code that just needs to propagate and annotate
|
|
49
|
+
errors up to `main`, not to dictate a precise error type to its own
|
|
50
|
+
callers.
|
|
51
|
+
|
|
52
|
+
## Traits and generics
|
|
53
|
+
|
|
54
|
+
- Accept the narrowest trait bound a function actually needs (`AsRef<str>`
|
|
55
|
+
over `&String`, `Iterator<Item = T>` over `Vec<T>`) so callers keep
|
|
56
|
+
flexibility in what they pass.
|
|
57
|
+
- Prefer returning a concrete type (`impl Trait` in return position) over
|
|
58
|
+
a boxed trait object (`Box<dyn Trait>`) unless runtime polymorphism
|
|
59
|
+
(a heterogeneous collection, a plugin-style callback list) is actually
|
|
60
|
+
needed — `impl Trait` avoids the allocation and indirection.
|
|
61
|
+
- Derive `Debug`, `Clone`, `PartialEq`, etc. instead of hand-writing them
|
|
62
|
+
when the type's fields support it; hand-write only when the derived
|
|
63
|
+
behavior would be wrong for the type's invariants.
|
|
64
|
+
|
|
65
|
+
## Iterators and control flow
|
|
66
|
+
|
|
67
|
+
- Prefer an iterator chain (`.map`/`.filter`/`.fold`/`.collect`) over a
|
|
68
|
+
hand-rolled indexed loop when it expresses the transformation as clearly
|
|
69
|
+
— but do not force a chain that reads worse than a plain `for` loop just
|
|
70
|
+
to look idiomatic; readability wins over either style has priority.
|
|
71
|
+
- Use pattern matching (`match`, `if let`, `let else`) to handle every
|
|
72
|
+
variant of an enum explicitly; avoid a catch-all `_ =>` arm on a `match`
|
|
73
|
+
over your own enum where a new variant should force every call site to
|
|
74
|
+
be revisited.
|
|
75
|
+
|
|
76
|
+
## Async conventions (when the crate uses async)
|
|
77
|
+
|
|
78
|
+
- `async fn` for I/O-bound work; never call a blocking operation
|
|
79
|
+
(`std::thread::sleep`, a synchronous file/socket read, a `std::sync`
|
|
80
|
+
primitive held across an `.await` point) inside an `async fn` running on
|
|
81
|
+
a multi-threaded executor — use the async equivalent (`tokio::time::sleep`,
|
|
82
|
+
`tokio::fs`, `tokio::sync::Mutex`) or `tokio::task::spawn_blocking` for
|
|
83
|
+
genuinely CPU-bound or blocking work.
|
|
84
|
+
- Keep a `Mutex` guard's scope as short as possible and never hold one
|
|
85
|
+
across an `.await`; prefer `tokio::sync::Mutex` when the lock itself
|
|
86
|
+
must be held across an await point, `std::sync::Mutex` when it never is.
|
|
87
|
+
|
|
88
|
+
## Formatting and lints
|
|
89
|
+
|
|
90
|
+
- Format with `rustfmt` (`cargo fmt`) before finishing a change; do not
|
|
91
|
+
hand-format around a formatter that is already configured.
|
|
92
|
+
- Run `cargo clippy -- -D warnings` and fix findings at the root cause
|
|
93
|
+
rather than adding a blanket `#[allow(...)]`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
extends: common
|
|
3
|
+
paths: ["**/*.rs"]
|
|
4
|
+
metadata:
|
|
5
|
+
origin: authored
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Rust patterns
|
|
9
|
+
|
|
10
|
+
Narrows `core-common-rules`' stack-agnostic design guidance to idiomatic
|
|
11
|
+
Rust design and its common anti-patterns. Applies only to `*.rs` files.
|
|
12
|
+
|
|
13
|
+
## Crate and module layout
|
|
14
|
+
|
|
15
|
+
- `src/lib.rs` (or `src/main.rs` for a binary) is the crate root; group
|
|
16
|
+
related functionality into modules under `src/`, each with a clear
|
|
17
|
+
single responsibility — a module that only holds shared types with no
|
|
18
|
+
behavior ("models", "types", "common") invites the same cross-module
|
|
19
|
+
coupling a Go "utils" package does.
|
|
20
|
+
- A workspace (`[workspace]` in the root `Cargo.toml`) splits genuinely
|
|
21
|
+
independent crates (a library plus a CLI that depends on it, or several
|
|
22
|
+
services sharing a core crate) — do not default to a workspace for a
|
|
23
|
+
single-binary project that has no reason to publish separate crates.
|
|
24
|
+
- Keep `pub` surface intentional: re-export the types callers need from
|
|
25
|
+
`lib.rs`, keep internal modules `pub(crate)` or private so the compiler
|
|
26
|
+
(not convention) enforces the boundary.
|
|
27
|
+
|
|
28
|
+
## Error handling design
|
|
29
|
+
|
|
30
|
+
- A library crate defines its own error enum with `thiserror`, one
|
|
31
|
+
variant per failure mode, `#[source]`/`#[from]` on any variant that
|
|
32
|
+
wraps another error so `source()` and `?`-based conversion both work —
|
|
33
|
+
never collapse distinct failure modes into a single `Other(String)`
|
|
34
|
+
variant that erases the caller's ability to match on what happened.
|
|
35
|
+
- An application/binary crate uses `anyhow::Result` at its outer layers
|
|
36
|
+
and `.context("doing x")`/`.with_context(|| ...)` at each call to `?`
|
|
37
|
+
that crosses a meaningful boundary, so a failure's final error chain
|
|
38
|
+
reads as a story, not a single opaque message.
|
|
39
|
+
- Never use a `Result<T, String>`/`Result<T, Box<dyn Error>>` as a
|
|
40
|
+
permanent design in a library — `Box<dyn Error>` is a reasonable
|
|
41
|
+
quick-prototype return type but forces every caller to string-match or
|
|
42
|
+
downcast; graduate to a concrete `thiserror` enum once the error shapes
|
|
43
|
+
stabilize.
|
|
44
|
+
|
|
45
|
+
## Ownership-driven API design
|
|
46
|
+
|
|
47
|
+
- Take `&self`/`&mut self`/`self` deliberately: `self` (by value) only
|
|
48
|
+
when the method consumes or transforms the value into something else
|
|
49
|
+
(a builder's terminal `.build()`), `&mut self` when it mutates in place,
|
|
50
|
+
`&self` otherwise.
|
|
51
|
+
- The typestate/builder pattern (a `FooBuilder` with chained `with_x`
|
|
52
|
+
methods returning `Self`, a terminal `.build() -> Result<Foo, ...>`) for
|
|
53
|
+
a constructor with many optional parameters, instead of a boolean-heavy
|
|
54
|
+
positional signature.
|
|
55
|
+
- Prefer newtypes (`struct UserId(u64);`) over a bare primitive when a
|
|
56
|
+
value has domain meaning distinct from its representation — the
|
|
57
|
+
compiler then rejects passing a `ProductId` where a `UserId` is
|
|
58
|
+
expected, which a bare `u64` parameter cannot.
|
|
59
|
+
|
|
60
|
+
## Trait design
|
|
61
|
+
|
|
62
|
+
- Define a trait at the point of abstraction a consumer actually needs
|
|
63
|
+
(an `impl Trait` argument or a generic bound), sized to the methods that
|
|
64
|
+
consumer calls — a trait with every method the concrete type happens to
|
|
65
|
+
have is not an abstraction, it is a restatement of the type.
|
|
66
|
+
- Prefer generics (`fn process<T: Processor>(p: &T)`) for a hot path where
|
|
67
|
+
monomorphization's code-size cost is acceptable and static dispatch
|
|
68
|
+
matters; use `Box<dyn Trait>`/`&dyn Trait` when you need a heterogeneous
|
|
69
|
+
collection or a boundary (a plugin registry, a callback list) where the
|
|
70
|
+
concrete type varies at runtime.
|
|
71
|
+
|
|
72
|
+
## Anti-patterns to flag
|
|
73
|
+
|
|
74
|
+
- A `.clone()` inserted to make the borrow checker pass without
|
|
75
|
+
considering whether restructuring ownership or borrowing differently
|
|
76
|
+
would avoid the copy — flag any clone in a hot path with no comment
|
|
77
|
+
explaining why it is necessary.
|
|
78
|
+
- Stringly-typed errors (`Err(format!("something went wrong: {e}"))`
|
|
79
|
+
returned as `Result<T, String>`) in a library crate instead of a
|
|
80
|
+
`thiserror`-derived enum a caller can match on.
|
|
81
|
+
- A "god module" (`utils`, `helpers`, `common`) accumulating unrelated
|
|
82
|
+
free functions — split by what the code actually does, the same
|
|
83
|
+
anti-pattern flagged in Go/Python's own pattern rules.
|
|
84
|
+
- `unwrap()`/`expect()` reached for as a shortcut past a type error during
|
|
85
|
+
development and never revisited before the change ships.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
extends: common
|
|
3
|
+
paths: ["**/*.rs"]
|
|
4
|
+
metadata:
|
|
5
|
+
origin: authored
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Rust security
|
|
9
|
+
|
|
10
|
+
Narrows `core-common-rules`' stack-agnostic security rules to Rust-specific,
|
|
11
|
+
OWASP-relevant risks and the safe standard-library/ecosystem API to use
|
|
12
|
+
instead. `unsafe` and panic-on-untrusted-input risks can appear anywhere a
|
|
13
|
+
crate touches attacker-influenced data, so this file stays broad rather
|
|
14
|
+
than narrowing to a single subdirectory.
|
|
15
|
+
|
|
16
|
+
## `unsafe` blocks
|
|
17
|
+
|
|
18
|
+
- Every `unsafe` block carries a `# Safety` doc comment (on the block or
|
|
19
|
+
the function containing it) stating the exact invariants the caller or
|
|
20
|
+
the block itself must uphold for the operation to be sound — not a
|
|
21
|
+
generic "this is safe" note, but the specific precondition (pointer
|
|
22
|
+
validity, alignment, lifetime, no concurrent mutation) that makes it so.
|
|
23
|
+
- Keep an `unsafe` block as small as possible — wrap only the operation
|
|
24
|
+
that actually requires it (a raw pointer deref, an FFI call, a
|
|
25
|
+
`mem::transmute`), not the surrounding safe code, so the audited surface
|
|
26
|
+
stays minimal.
|
|
27
|
+
- Never widen an `unsafe` block or drop its `# Safety` comment to silence
|
|
28
|
+
a compiler or clippy complaint; if the invariant cannot be stated, the
|
|
29
|
+
code is not actually sound and needs a different approach.
|
|
30
|
+
|
|
31
|
+
## Panics on untrusted input
|
|
32
|
+
|
|
33
|
+
- Never call `.unwrap()`/`.expect()` on a `Result`/`Option` derived from
|
|
34
|
+
network input, file contents, CLI arguments, or any other
|
|
35
|
+
attacker-influenced source — a panic there is a denial-of-service vector
|
|
36
|
+
(the process/thread aborts) even when the underlying bug is minor.
|
|
37
|
+
Propagate with `?`, or handle explicitly.
|
|
38
|
+
- Guard array/slice indexing on untrusted-derived indices with `.get(i)`
|
|
39
|
+
(returns `Option`) instead of `arr[i]` (panics out of bounds); guard
|
|
40
|
+
integer arithmetic on untrusted values with `checked_add`/`checked_mul`/
|
|
41
|
+
`saturating_*`/`wrapping_*` as the operation's semantics require, instead
|
|
42
|
+
of a bare `+`/`*` that panics on overflow in debug builds and silently
|
|
43
|
+
wraps in release builds — both are wrong for a value an attacker
|
|
44
|
+
influences.
|
|
45
|
+
|
|
46
|
+
## FFI boundaries
|
|
47
|
+
|
|
48
|
+
- Validate every value crossing an `extern "C"` boundary before trusting
|
|
49
|
+
it — a raw pointer from C is not guaranteed non-null, valid, or
|
|
50
|
+
correctly aligned; check before dereferencing, and document the
|
|
51
|
+
ownership/lifetime contract (who frees it, using what allocator) in the
|
|
52
|
+
function's `# Safety` comment.
|
|
53
|
+
- Never let a Rust panic unwind across an `extern "C"` boundary — undefined
|
|
54
|
+
behavior in most toolchains; catch it with `std::panic::catch_unwind` at
|
|
55
|
+
the FFI edge and convert it to an error code instead.
|
|
56
|
+
|
|
57
|
+
## Dependency and supply-chain hygiene
|
|
58
|
+
|
|
59
|
+
- Run `cargo audit` (or the project's already-configured equivalent) when
|
|
60
|
+
introducing or updating a dependency, or when asked to check for known
|
|
61
|
+
vulnerabilities — it checks `Cargo.lock` against the RustSec advisory
|
|
62
|
+
database.
|
|
63
|
+
- Pin dependency versions deliberately in `Cargo.toml`; avoid a bare `*`
|
|
64
|
+
or an overly wide range that lets an unreviewed major/minor bump in.
|
|
65
|
+
|
|
66
|
+
## Deserialization
|
|
67
|
+
|
|
68
|
+
- When deserializing untrusted input with `serde`, apply size/depth limits
|
|
69
|
+
appropriate to the format and deserializer (a bounded reader, a
|
|
70
|
+
recursion-depth guard, or the deserializer's own limit configuration
|
|
71
|
+
where it exposes one) — an unbounded deserialize of attacker-controlled
|
|
72
|
+
JSON/bincode/etc. is a memory-exhaustion or stack-overflow
|
|
73
|
+
(deeply-nested structures) vector.
|
|
74
|
+
- Never derive `Deserialize` for a type and then trust its field values
|
|
75
|
+
as pre-validated — validate ranges/formats/invariants after
|
|
76
|
+
deserializing, the same as any other externally-sourced value.
|
|
77
|
+
|
|
78
|
+
## Randomness and secrets
|
|
79
|
+
|
|
80
|
+
- Use a CSPRNG (the `rand` crate's default `ThreadRng`/`OsRng`, or the
|
|
81
|
+
`getrandom`/`ring` crates) for anything security-sensitive — tokens,
|
|
82
|
+
session IDs, keys, nonces; a non-cryptographic PRNG seeded predictably
|
|
83
|
+
is unsuitable for secrets even when its API looks the same.
|
|
84
|
+
- Never hard-code a credential, API key, or signing secret in source; load
|
|
85
|
+
it from environment/secret storage the project already uses.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
extends: common
|
|
3
|
+
paths: ["**/*.rs"]
|
|
4
|
+
metadata:
|
|
5
|
+
origin: authored
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Rust testing
|
|
9
|
+
|
|
10
|
+
Narrows `core-common-rules`' stack-agnostic testing rules to Rust's built-in
|
|
11
|
+
`#[test]` framework and its common extensions. Applies only to `*.rs` files.
|
|
12
|
+
|
|
13
|
+
## Layout and naming
|
|
14
|
+
|
|
15
|
+
- Unit tests live in a `#[cfg(test)] mod tests { use super::*; ... }` block
|
|
16
|
+
at the bottom of the file they test, giving them access to private
|
|
17
|
+
items; integration tests (exercising only the crate's public API) live
|
|
18
|
+
under `tests/` at the crate root, one file per test binary.
|
|
19
|
+
- Name a test function for the behavior it verifies
|
|
20
|
+
(`rejects_negative_amount`, not `test1` or `test_validate`); group
|
|
21
|
+
related cases as separate `#[test]` functions or, for many similar
|
|
22
|
+
inputs, a parameterized loop/table within one function.
|
|
23
|
+
- Fixture/golden data a test reads lives under `tests/fixtures/` (or a
|
|
24
|
+
crate-local `testdata/` if the project already uses that convention) —
|
|
25
|
+
match whatever the crate already does rather than inventing a new one.
|
|
26
|
+
|
|
27
|
+
## Test structure
|
|
28
|
+
|
|
29
|
+
- Prefer a small table of cases (a `Vec` of a local struct, or a slice of
|
|
30
|
+
tuples) iterated in one `#[test]` function over many near-duplicate test
|
|
31
|
+
functions, when the cases share the same assertion shape — mirrors the
|
|
32
|
+
table-driven convention from other stacks, adapted to Rust's lack of a
|
|
33
|
+
built-in subtest runner.
|
|
34
|
+
- Assert with `assert_eq!`/`assert!`/`assert_ne!` from `std`, or the
|
|
35
|
+
project's already-adopted assertion crate (`pretty_assertions`,
|
|
36
|
+
`assert_matches`) — do not introduce a new assertion library into a
|
|
37
|
+
crate that has not adopted one.
|
|
38
|
+
- For a `Result`-returning function, assert the specific error variant
|
|
39
|
+
(`assert!(matches!(err, MyError::NotFound { .. }))` or
|
|
40
|
+
`assert_eq!(err, MyError::NotFound)` when the error implements
|
|
41
|
+
`PartialEq`) rather than only `assert!(result.is_err())`, which passes
|
|
42
|
+
for the wrong failure just as readily as the right one.
|
|
43
|
+
|
|
44
|
+
## Async tests
|
|
45
|
+
|
|
46
|
+
- `#[tokio::test]` (or the project's already-configured async test
|
|
47
|
+
attribute) for an `async fn` test body; never block a `#[test]`
|
|
48
|
+
function's thread on a future with a hand-rolled executor when the
|
|
49
|
+
project already depends on `tokio`.
|
|
50
|
+
- Join spawned tasks with `.await` on their `JoinHandle`, or a channel,
|
|
51
|
+
before asserting — never synchronize with `std::thread::sleep`/
|
|
52
|
+
`tokio::time::sleep` to "give a spawned task time to finish"; that is
|
|
53
|
+
non-deterministic under load and flakes in CI exactly like a Go test
|
|
54
|
+
that sleeps instead of joining a goroutine.
|
|
55
|
+
|
|
56
|
+
## Property-based and fuzz testing
|
|
57
|
+
|
|
58
|
+
- Reach for `proptest` or `quickcheck` (whichever the crate already
|
|
59
|
+
depends on) for a function with a large, structured input space
|
|
60
|
+
(a parser, a serializer round-trip) instead of hand-writing dozens of
|
|
61
|
+
near-identical example-based cases.
|
|
62
|
+
- `cargo fuzz` (built on `libFuzzer`) for a parser or decoder that touches
|
|
63
|
+
untrusted input formats directly; note in the report that fuzzing runs
|
|
64
|
+
separately from `cargo test` and is not part of the default CI test run
|
|
65
|
+
unless the project has wired it in.
|
|
66
|
+
|
|
67
|
+
## Benchmarks
|
|
68
|
+
|
|
69
|
+
- Use `criterion` (the de facto ecosystem standard) for a benchmark that
|
|
70
|
+
needs statistical rigor (warm-up, outlier detection, regression
|
|
71
|
+
comparison across runs) rather than the unstable built-in `#[bench]`
|
|
72
|
+
attribute, which requires nightly.
|
|
73
|
+
|
|
74
|
+
## Running and determinism
|
|
75
|
+
|
|
76
|
+
- Run `cargo test` (add `--all-features`/`--workspace` when the project's
|
|
77
|
+
CI does) before reporting tests as passing; a test relying on wall-clock
|
|
78
|
+
timing, real network access, or shared global state is a flake risk —
|
|
79
|
+
prefer a fake clock, a mock boundary, or `#[serial]` (from the `serial_test`
|
|
80
|
+
crate) for tests that must not run concurrently.
|
|
81
|
+
- New behavior gets a new test in the same change; a bug fix gets a
|
|
82
|
+
regression test that fails before the fix and passes after.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-build-fix
|
|
3
|
+
description: "Use when cargo build/cargo clippy fails, or Cargo.toml/Cargo.lock are out of sync -- resolves dependency/edition/MSRV mismatches, borrow-checker and lifetime errors, trait-bound errors, clippy failures, and a failing cargo test, with the smallest root-cause fix."
|
|
4
|
+
triggers:
|
|
5
|
+
- "cargo build is failing"
|
|
6
|
+
- "fix Cargo.toml Cargo.lock mismatch"
|
|
7
|
+
- "resolve this Rust borrow checker error"
|
|
8
|
+
- "cargo clippy is failing"
|
|
9
|
+
- "this Rust trait bound isn't satisfied"
|
|
10
|
+
- "cargo test is failing"
|
|
11
|
+
metadata:
|
|
12
|
+
origin: authored
|
|
13
|
+
category: build-fix
|
|
14
|
+
version: "1.0.0"
|
|
15
|
+
compatible_harnesses: "claude,codex,cursor,zed,opencode"
|
|
16
|
+
license: "MIT"
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Rust build fix (2021/2024 edition)
|
|
20
|
+
|
|
21
|
+
Resolve a `cargo build`/`cargo clippy` failure, a `Cargo.toml`/`Cargo.lock`
|
|
22
|
+
mismatch, a borrow-checker/lifetime error, an unsatisfied trait bound, or a
|
|
23
|
+
failing `cargo test` — with the smallest change that fixes the actual root
|
|
24
|
+
cause. `rules/coding-style.mdc` and `rules/security.mdc` govern what a
|
|
25
|
+
"correct" fix looks like; this skill never reaches for a suppression
|
|
26
|
+
instead of a fix.
|
|
27
|
+
|
|
28
|
+
## Workflow
|
|
29
|
+
|
|
30
|
+
### Step 1: Reproduce and classify
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cargo build --all-targets
|
|
34
|
+
cargo clippy --all-targets -- -D warnings
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Read the exact error text (`rustc`'s diagnostics name the error code, e.g.
|
|
38
|
+
`E0502`, `E0308`) and classify it:
|
|
39
|
+
|
|
40
|
+
- **Compile error** (type mismatch, undefined item, wrong argument count).
|
|
41
|
+
- **Borrow checker / lifetime** (`E0502` conflicting borrows, `E0499`
|
|
42
|
+
multiple mutable borrows, a lifetime that doesn't live long enough).
|
|
43
|
+
- **Trait bound** (`the trait bound ... is not satisfied`, a missing
|
|
44
|
+
`impl` the code assumes exists).
|
|
45
|
+
- **Dependency/edition/MSRV** (`Cargo.lock` stale against `Cargo.toml`,
|
|
46
|
+
a version conflict, a feature used past the declared `edition`/
|
|
47
|
+
`rust-version`).
|
|
48
|
+
- **Clippy finding** (a lint from `cargo clippy`'s default set or the
|
|
49
|
+
project's configured groups).
|
|
50
|
+
- **Test failure** (`cargo test` reports a failing assertion or panic).
|
|
51
|
+
|
|
52
|
+
### Step 2: Fix by category
|
|
53
|
+
|
|
54
|
+
**Dependency/edition/MSRV:** run `cargo update -p <crate>` for a targeted
|
|
55
|
+
bump, or `cargo update` for a full re-resolve, when `Cargo.lock` is simply
|
|
56
|
+
stale against `Cargo.toml`'s requirements. For a genuine version conflict,
|
|
57
|
+
check `cargo tree -i <crate>` (what depends on the conflicting version)
|
|
58
|
+
before bumping by hand. Only raise `edition`/`rust-version` in
|
|
59
|
+
`Cargo.toml` when the code genuinely needs a feature that edition/MSRV
|
|
60
|
+
introduces, and say so in the report — never to make an unrelated error
|
|
61
|
+
disappear.
|
|
62
|
+
|
|
63
|
+
**Borrow checker / lifetime:** read what the compiler's own suggestion
|
|
64
|
+
proposes first (`rustc` usually names the exact conflicting borrows or
|
|
65
|
+
missing lifetime). Prefer restructuring ownership, splitting a borrow, or
|
|
66
|
+
shortening a lifetime over reaching for `.clone()`; a clone is an
|
|
67
|
+
acceptable fix only when the value genuinely needs to be duplicated —
|
|
68
|
+
say so in the report either way (`rules/patterns.mdc`).
|
|
69
|
+
|
|
70
|
+
**Trait bound:** check whether the missing `impl` should exist on the
|
|
71
|
+
type in question (derive it, or implement it) versus whether the calling
|
|
72
|
+
code's generic bound is wider than it needs to be. Do not add a blanket
|
|
73
|
+
bound or an unnecessary `Box<dyn Trait>` conversion just to make the
|
|
74
|
+
compiler stop complaining without understanding which side is wrong.
|
|
75
|
+
|
|
76
|
+
**Clippy finding:** fix the underlying issue the lint names (an
|
|
77
|
+
unnecessary clone, a `.unwrap()` on fallible input, a needless
|
|
78
|
+
collect). Never add `#[allow(clippy::...)]` or a blanket
|
|
79
|
+
`#[allow(clippy::all)]` whose only purpose is to make the checker stop
|
|
80
|
+
complaining without addressing what it found.
|
|
81
|
+
|
|
82
|
+
**Test failure:** read the assertion output and the code path it
|
|
83
|
+
exercises; fix the actual bug the test caught. Never delete, skip
|
|
84
|
+
(`#[ignore]`), or loosen the assertion to reach a green build unless the
|
|
85
|
+
test itself is proven wrong (say so explicitly in the report).
|
|
86
|
+
|
|
87
|
+
### Step 3: Verify
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
cargo build --all-targets
|
|
91
|
+
cargo clippy --all-targets -- -D warnings
|
|
92
|
+
cargo fmt --check
|
|
93
|
+
cargo test
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
All must exit 0 before reporting done.
|
|
97
|
+
|
|
98
|
+
### Step 4: Report
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Fixed: Cargo.lock stale against a version bump in Cargo.toml (ran `cargo update -p tokio`)
|
|
102
|
+
- Root cause: Cargo.lock predated a minor version bump in Cargo.toml
|
|
103
|
+
- cargo build/clippy -D warnings/fmt --check/test all pass
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
State the root cause in one sentence, not just "fixed the error."
|
|
107
|
+
|
|
108
|
+
## Rules
|
|
109
|
+
|
|
110
|
+
- Find and fix the smallest change that addresses the actual root cause —
|
|
111
|
+
never widen a fix beyond what the failure requires.
|
|
112
|
+
- NEVER add `#[allow(clippy::...)]` (especially a blanket
|
|
113
|
+
`#[allow(clippy::all)]`) to silence a clippy finding instead of fixing
|
|
114
|
+
what it found.
|
|
115
|
+
- NEVER raise `edition`/`rust-version` in `Cargo.toml`, or bump a major
|
|
116
|
+
dependency version, just to make an error disappear without
|
|
117
|
+
understanding why it changed.
|
|
118
|
+
- NEVER reach for `.clone()`/`.unwrap()` purely to make the compiler stop
|
|
119
|
+
complaining without considering whether it addresses the actual error.
|
|
120
|
+
- NEVER delete, skip (`#[ignore]`), or loosen an assertion to reach a
|
|
121
|
+
green `cargo test`.
|
|
122
|
+
|
|
123
|
+
## Red Flags
|
|
124
|
+
|
|
125
|
+
| Rationalization | Why it is wrong |
|
|
126
|
+
|---|---|
|
|
127
|
+
| "I'll add `#[allow(clippy::redundant_clone)]` here so the linter stops complaining" | Silences the finding without addressing whether the clone is actually needed; check the ownership shape instead. `redundant_clone` lives in clippy's `nursery` group (allow-by-default), so it only surfaces when that group is enabled -- but once it fires, suppressing it is the same mistake as suppressing any other clippy finding |
|
|
128
|
+
| "Bumping the edition to 2024 makes this compile" | Changes the crate's declared minimum edition for every consumer to dodge one error; understand why the code needs 2024 first, or fix the code to work at the declared edition |
|
|
129
|
+
| "This test is flaky, I'll add `#[ignore]` for now" | Hides a real bug or a real flake source instead of fixing the underlying issue; find the actual cause |
|
|
130
|
+
| "I'll just `.clone()` past this borrow error" | A reflexive clone can mask an ownership design issue the compiler is correctly catching; read the compiler's own suggestion first |
|
|
131
|
+
|
|
132
|
+
## Verification
|
|
133
|
+
|
|
134
|
+
Do not report the fix done until all of the following hold:
|
|
135
|
+
|
|
136
|
+
- `cargo build --all-targets`, `cargo clippy --all-targets -- -D warnings`,
|
|
137
|
+
`cargo fmt --check`, and `cargo test` all exit 0.
|
|
138
|
+
- The change is the smallest one that addresses the stated root cause —
|
|
139
|
+
no unrelated files touched.
|
|
140
|
+
- The report states the root cause in one sentence, not just "build now
|
|
141
|
+
passes."
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"triggers": {
|
|
3
|
+
"positive": [
|
|
4
|
+
"cargo build is failing with a trait bound not satisfied error",
|
|
5
|
+
"I bumped a dependency version and now cargo build complains the lockfile doesn't match Cargo.toml anymore, what do I do?",
|
|
6
|
+
"The compiler won't let me borrow `orders` as mutable twice at the same time in this function, how do I restructure it so it compiles?",
|
|
7
|
+
"cargo clippy is reporting a needless clone lint",
|
|
8
|
+
"This Rust code has a lifetime error that won't compile",
|
|
9
|
+
"cargo test is failing with a panic in the order crate, fix the build"
|
|
10
|
+
],
|
|
11
|
+
"negative": [
|
|
12
|
+
"npm install is failing with a peer dependency conflict",
|
|
13
|
+
"go build is failing for this Go module",
|
|
14
|
+
"pip install is failing for this Python project",
|
|
15
|
+
"Implement a new Rust feature in the order crate",
|
|
16
|
+
"Review this Rust diff for unsafe blocks and unwrap panics",
|
|
17
|
+
"Write Rust tests for this function",
|
|
18
|
+
"Our CMake configure step is failing with a missing header error"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"scenarios": [
|
|
22
|
+
{
|
|
23
|
+
"id": "lockfile-mismatch",
|
|
24
|
+
"prompt": "cargo build --locked fails saying Cargo.lock is out of date after I bumped a dependency version in Cargo.toml (this is the same command our CI runs). How do I fix it?",
|
|
25
|
+
"strictness": "high",
|
|
26
|
+
"expected_behavior": [
|
|
27
|
+
{
|
|
28
|
+
"grader": "judge",
|
|
29
|
+
"rubric": "A correct answer identifies that Cargo.lock is stale relative to Cargo.toml's requirements after the dependency bump and fixes it by running cargo update (or a targeted cargo update -p <crate>). For a genuine version conflict it checks cargo tree -i <crate> before bumping another dependency's version by hand, rather than routing around the error some other way.",
|
|
30
|
+
"pass_criteria": [
|
|
31
|
+
"Names `cargo update` or `cargo update -p <crate>`, run from the crate/workspace root, as the concrete command that resolves the stale Cargo.lock -- not merely 'sync the files' or 'run the tool that fixes this'.",
|
|
32
|
+
"States the root cause: Cargo.lock no longer matches what Cargo.toml now requires after the version bump, not just 'run this command' with no explanation.",
|
|
33
|
+
"Either names a concrete verification step afterward (`cargo build`/`cargo test`) or does not suggest skipping verification."
|
|
34
|
+
],
|
|
35
|
+
"fail_criteria": [
|
|
36
|
+
"Recommends raising the `edition` or `rust-version` in Cargo.toml to make the error go away, or bumping another dependency's version by hand without checking what depends on it, as a substitute for running `cargo update`.",
|
|
37
|
+
"Recommends hand-editing the checksum/version lines in Cargo.lock directly instead of regenerating it with `cargo update`."
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"calibration": {
|
|
42
|
+
"known_right": "This means Cargo.lock no longer matches what Cargo.toml now requires after you bumped the dependency version. The fix is `cargo update -p <crate-name>` (or a plain `cargo update` if you want everything re-resolved) run from the crate or workspace root -- it recomputes Cargo.lock against Cargo.toml's requirements, picking up the new version and resolving anything that needs to shift alongside it. If the bump pulls in a genuine version conflict rather than a simple stale-lock error, don't just bump another crate's version by hand -- run `cargo tree -i <conflicting-crate>` first to see what's actually pinning the conflicting version, so you understand the dependency shape before changing it. After `cargo update` finishes, re-run `cargo build` and `cargo test` to confirm everything is consistent again before considering this done. Avoid hand-editing the checksums or version lines in Cargo.lock directly; that file is generated and meant to be regenerated by tooling, not patched by hand.",
|
|
43
|
+
"known_wrong": "Honestly the fastest fix here is to bump the edition in Cargo.toml to \"2024\" -- that usually makes Cargo.lock errors like this go away without you needing to figure out what `cargo update` would even change. Just edit the `edition = \"2021\"` line and re-run the build; if it still complains, bump another dependency's version in Cargo.toml up a bit further too until the error clears. You don't really need to run `cargo tree` or dig into the dependency graph for a simple lockfile mismatch like this -- that's overkill for what's usually just a version string being out of date.",
|
|
44
|
+
"vague": "This is just a dependency sync issue -- make sure your Cargo files are consistent with each other again and the build should pass.",
|
|
45
|
+
"subtle_wrong": "Bump the dependency's version in Cargo.toml directly to match what your code now needs, then try `cargo build` again -- if Cargo.lock still complains about a missing checksum for that version, add the missing hash/version entry to Cargo.lock by hand so the two files line up. That gets you to a green build without having to run `cargo update` and re-resolve everything else it might touch."
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "no-clippy-allow-suppression",
|
|
50
|
+
"prompt": "cargo clippy (with the nursery group enabled) is flagging a redundant clone in my Rust code. How should I fix it?",
|
|
51
|
+
"strictness": "high",
|
|
52
|
+
"expected_behavior": [
|
|
53
|
+
{
|
|
54
|
+
"grader": "judge",
|
|
55
|
+
"rubric": "A correct answer fixes the actual redundant clone -- removes it and borrows instead, or restructures ownership so the clone isn't needed -- instead of suppressing the lint with #[allow(clippy::...)] (especially a blanket #[allow(clippy::all)]), and instead of keeping the clone with only a comment explaining it away when the lint indicates it is genuinely unnecessary.",
|
|
56
|
+
"pass_criteria": [
|
|
57
|
+
"Identifies that the clone is unnecessary and should be removed in favor of borrowing (a reference) or restructuring ownership, not kept.",
|
|
58
|
+
"Shows the concrete fix direction: pass a reference (e.g. `&value` or changing the parameter type to `&T`) instead of the owned clone, or an equivalent restructuring -- not merely a statement that the clone 'should be looked at'.",
|
|
59
|
+
"Does not rely on `#[allow(clippy::...)]` (or a blanket `#[allow(clippy::all)]`) as the fix for the flagged finding."
|
|
60
|
+
],
|
|
61
|
+
"fail_criteria": [
|
|
62
|
+
"Recommends adding `#[allow(clippy::redundant_clone)]` or `#[allow(clippy::all)]` to silence the finding instead of removing the clone.",
|
|
63
|
+
"Keeps the clone unchanged and only adds a comment justifying it, when the lint's own message indicates the value can simply be borrowed instead."
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"calibration": {
|
|
68
|
+
"known_right": "clippy's `redundant_clone` (part of the `nursery` group, allow-by-default, which is why it only shows up once that group is enabled) is telling you the value gets duplicated somewhere it could just be borrowed instead -- that usually means a function parameter or a call site is taking ownership (`T` or `.clone()`) where a reference (`&T`) would work just as well. Look at how the cloned value is used afterward: if the caller still needs its own copy and the callee only reads the value, change the callee's signature to accept `&T` and drop the `.clone()` at the call site. If the callee genuinely needs to own or mutate its own copy independent of the caller, the clone might be legitimate -- in that case leave it, but consider whether an owned move (transferring ownership instead of cloning) is possible if the caller doesn't need the value afterward either. Don't reach for `#[allow(clippy::redundant_clone)]` here -- that just tells the linter to stop looking, it doesn't address whether the clone was actually needed. Once you've fixed it, re-run `cargo clippy -- -D warnings` (with the nursery group enabled) to confirm the finding is actually resolved rather than merely hidden.",
|
|
69
|
+
"known_wrong": "The simplest fix is to just add `#[allow(clippy::redundant_clone)]` above the function -- that clone genuinely doesn't matter here for a value this small, and it stops clippy from flagging it every time CI runs. You don't need to touch the actual signature or figure out whether borrowing would work; the allow attribute is exactly what it's for. If clippy flags something similar nearby, you can add the same allow there too rather than working through each clone individually.",
|
|
70
|
+
"vague": "You should fix that clone properly instead of suppressing the finding -- make sure it's actually addressed before you call this done.",
|
|
71
|
+
"subtle_wrong": "That redundant_clone finding is easy to clear without touching the surrounding logic: leave the `.clone()` exactly where it is and add a comment above it explaining that it's there for simplicity, so future readers understand it's intentional. That way you're not silently ignoring clippy's feedback anymore, and you don't have to change the function's signature or verify that borrowing would actually work at every call site."
|
|
72
|
+
},
|
|
73
|
+
"anti_patterns": [
|
|
74
|
+
"#[allow(clippy"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|