Skip to content

Commit 2ce9eb4

Browse files
karthiknadigCopilot
andcommitted
docs: strengthen PET Rust review guidance (Fixes #496)
Capture recurring path identity, Unicode parsing, hot-path I/O, side-effect, and behavior-test checks from recent PR reviews. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b618197 commit 2ce9eb4

2 files changed

Lines changed: 118 additions & 0 deletions

File tree

.github/agents/Reviewer.agent.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ Automated reviews consistently miss:
3535
- Thread safety issues with shared state
3636
- JSONRPC protocol violations (stdout contamination)
3737
- Performance regressions from spawning Python processes
38+
- Path-keyed caches that normalize keys inconsistently or return stale caller-facing paths
39+
- Unicode-unsafe byte indexing and unnecessary hot-path allocations
40+
- Tests that execute code without proving the claimed I/O or allocation reduction
41+
- Duplicate warnings, reports, or telemetry emitted from overlapping paths
3842

3943
---
4044

@@ -44,6 +48,8 @@ Automated reviews consistently miss:
4448

4549
Before reading code:
4650

51+
- If any changed file is Rust, load and apply both `.github/skills/rust-coding-skill/SKILL.md` and `.github/skills/rust-locator-patterns/SKILL.md`.
52+
4753
- What issue does this change claim to fix?
4854
- Which locator/crate is affected?
4955
- Does it touch identification logic (`try_from`) or discovery logic (`find`)?
@@ -162,6 +168,35 @@ let mut environments = self.environments
162168
- No deadlock potential from nested locks
163169
- Consider using `thread::scope` for structured concurrency
164170

171+
### General Rust Correctness and Performance
172+
173+
Apply `.github/skills/rust-coding-skill/SKILL.md` to every Rust review, not only locator changes.
174+
175+
**Path-keyed state:**
176+
177+
- Are lookup, insert, remove, prune, and sync keys normalized consistently?
178+
- Does a cache hit preserve the current caller's user-facing path rather than leaking the first cached spelling?
179+
- Is there Windows coverage for equivalent casing or separators?
180+
181+
**Parsing:**
182+
183+
- Are byte offsets computed from the same string being sliced?
184+
- If markers are ASCII, does the code use byte-stable ASCII matching and checked `str::get` slicing?
185+
- Is there a non-ASCII regression case around paths or names?
186+
187+
**Hot paths:**
188+
189+
- Does the implementation read each metadata file once per logical operation?
190+
- Did the author trace root/base and manager call paths, not just the common environment path?
191+
- Are borrowed snapshots passed through instead of reopening files or cloning strings?
192+
- Can `rfind`, `find_map`, or streaming output replace an intermediate `Vec` or `String`?
193+
194+
**Side effects and tests:**
195+
196+
- Can a warning, notification, manager, or environment be emitted twice by pre-check and worker paths?
197+
- Does the test assert the claimed invariant (read count, cache hit, event count), not just the final value?
198+
- Are classification boundaries covered (`**` path segment vs `foo**bar`, valid vs malformed markers)?
199+
165200
### Platform-Specific Code
166201

167202
**Use the correct conditional compilation:**
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
name: "rust-coding-skill"
3+
description: "Use whenever editing Rust in PET to write allocation-aware, cross-platform, byte-safe code with behavior-proving tests."
4+
user-invocable: true
5+
---
6+
7+
# PET Rust Coding Skill
8+
9+
Use this alongside `rust-locator-patterns`. Priority order:
10+
11+
1. Readable code with explicit invariants
12+
2. Correct cross-platform and concurrent behavior
13+
3. Measured performance improvements without duplicate work
14+
15+
## Path Identity and Caches
16+
17+
Use `Path`/`PathBuf` for paths. Preserve the caller-facing path in reported values, but normalize cache and comparison keys with existing PET helpers such as `norm_case`.
18+
19+
A normalized key does not imply the cached value can expose the first caller's spelling:
20+
21+
```rust
22+
let key = norm_case(path);
23+
let mut cached = cache.get(&key)?.clone();
24+
cached.prefix = Some(path.to_path_buf());
25+
```
26+
27+
When adding or reviewing a path-keyed cache, check lookup, insert, remove, retain/prune, and state-sync paths. Add Windows coverage using equivalent separators or casing; do not test only the happy-path spelling.
28+
29+
## Byte-Safe Parsing
30+
31+
Never calculate byte offsets from a transformed Unicode string and apply them to the original. Unicode case conversion can change byte length.
32+
33+
For ASCII wire/file markers, use byte-stable ASCII-insensitive matching and checked slicing:
34+
35+
```rust
36+
let start = find_ascii_case_insensitive(line, "# cmd:")? + "# cmd:".len();
37+
let end = find_ascii_case_insensitive(line, " create -")?;
38+
let value = line.get(start..end)?.trim();
39+
```
40+
41+
Use `to_ascii_lowercase` rather than `to_lowercase` when the format is defined as ASCII. Add a non-ASCII path regression test whenever offsets are derived from textual markers.
42+
43+
## Hot-Path I/O and Allocations
44+
45+
Discovery runs frequently and in parallel. Before adding a cache, prove the repeated work and define invalidation. Within one operation, read immutable metadata once and pass borrowed snapshots through parsers.
46+
47+
- Prefer `&str`/`&[u8]` over cloning content between parsers.
48+
- Prefer `rfind`/iterator operations over collecting an intermediate `Vec` just to select one item.
49+
- Avoid `format!` and Unicode case conversion in per-line loops when ASCII matching or direct writes suffice.
50+
- Do not claim an optimization is complete until every relevant call path is traced, including base/root environments and manager lookup.
51+
- Do not emit the same warning, telemetry event, or report from both a pre-check and the worker path.
52+
53+
## Error Handling and Locks
54+
55+
Library code should preserve typed information where repository APIs permit it. Prefer `?`, `let-else`, and `if let` over broad fallbacks. Do not swallow filesystem errors when doing so can make stale cache data look valid.
56+
57+
Use contextual `expect` for poisoned locks in production code, matching the surrounding crate. Keep lock scopes short and never perform filesystem I/O or callbacks while holding a shared-state lock unless the design explicitly requires it.
58+
59+
## Cross-Platform Semantics
60+
61+
- Use `#[cfg(...)]` for platform-only code; `cfg!` does not prevent compilation.
62+
- Avoid `canonicalize` for Windows junction identity; use PET path helpers.
63+
- Treat both `/` and `\` as separators when parsing user patterns, but only classify `**` as recursive when it is a complete path segment. `foo**bar` is not a recursive segment.
64+
- Preserve original user-facing paths after normalized comparisons.
65+
66+
## Tests Must Prove the Change
67+
68+
Tests should demonstrate the behavior or performance invariant, not merely execute new lines.
69+
70+
For optimizations, instrument the dependency boundary and assert the operation count:
71+
72+
```rust
73+
let reads = Cell::new(0);
74+
parse_with_reader(path, |_| {
75+
reads.set(reads.get() + 1);
76+
Some(history.clone())
77+
});
78+
assert_eq!(reads.get(), 1);
79+
```
80+
81+
For parser helpers, include malformed input, non-ASCII surrounding data, and case variations. For diagnostics, test pattern classification and expansion filtering separately. Keep temp paths unique with `tempfile` or process/counter-based names.
82+
83+
Before every Rust commit, run the targeted tests plus `scripts/rust-precommit.ps1` (or `.sh`). Do not suppress Clippy warnings to land a change.

0 commit comments

Comments
 (0)