-
Notifications
You must be signed in to change notification settings - Fork 41
docs: strengthen PET Rust review guidance (Fixes #496) #497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+124
−0
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2ce9eb4
docs: strengthen PET Rust review guidance (Fixes #496)
karthiknadig c4f83c9
docs: address Rust skill review feedback (PR #497)
karthiknadig 9f190ff
docs: capture config semantics review lesson (PR #497)
karthiknadig fba43a6
docs: reference Rust skills by name (PR #497)
karthiknadig f0dccc3
docs: scope locator review guidance (PR #497)
karthiknadig a15c586
Merge branch 'main' into chore/issue-496
karthiknadig File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| --- | ||
| name: "rust-coding-skill" | ||
| description: "Use whenever editing Rust in PET to write allocation-aware, cross-platform, byte-safe code with behavior-proving tests." | ||
| --- | ||
|
|
||
| # PET Rust Coding Skill | ||
|
|
||
| Use this alongside `rust-locator-patterns`. Priority order: | ||
|
|
||
| 1. Readable code with explicit invariants | ||
| 2. Correct cross-platform and concurrent behavior | ||
| 3. Measured performance improvements without duplicate work | ||
|
|
||
| ## Path Identity and Caches | ||
|
|
||
| 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`. | ||
|
|
||
| A normalized key does not imply the cached value can expose the first caller's spelling: | ||
|
|
||
| ```rust | ||
| let key = norm_case(path); | ||
| let mut cached = cache.get(&key)?.clone(); | ||
| cached.prefix = Some(path.to_path_buf()); | ||
| ``` | ||
|
|
||
| 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. | ||
|
|
||
| ## Byte-Safe Parsing | ||
|
|
||
| Never calculate byte offsets from a transformed Unicode string and apply them to the original. Unicode case conversion can change byte length. | ||
|
|
||
| For ASCII wire/file markers, use byte-stable ASCII-insensitive matching and checked slicing: | ||
|
|
||
| ```rust | ||
| let marker = b"# cmd:"; | ||
| let start = line | ||
| .as_bytes() | ||
| .windows(marker.len()) | ||
| .position(|window| window.eq_ignore_ascii_case(marker))? | ||
| + marker.len(); | ||
| let value = line.get(start..)?.trim(); | ||
| ``` | ||
|
|
||
| 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. | ||
|
|
||
| ## Hot-Path I/O and Allocations | ||
|
|
||
| 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. | ||
|
|
||
| - Prefer `&str`/`&[u8]` over cloning content between parsers. | ||
| - Prefer `rfind`/iterator operations over collecting an intermediate `Vec` just to select one item. | ||
| - Avoid `format!` and Unicode case conversion in per-line loops when ASCII matching or direct writes suffice. | ||
| - Do not claim an optimization is complete until every relevant call path is traced, including base/root environments and manager lookup. | ||
| - Do not emit the same warning, telemetry event, or report from both a pre-check and the worker path. | ||
|
|
||
| ## Error Handling and Locks | ||
|
|
||
| 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. | ||
|
|
||
| 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. | ||
|
|
||
| ## Cross-Platform Semantics | ||
|
|
||
| - Use `#[cfg(...)]` for platform-only code; `cfg!` does not prevent compilation. | ||
| - Avoid `canonicalize` for Windows junction identity; use PET path helpers. | ||
| - 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. | ||
| - Preserve original user-facing paths after normalized comparisons. | ||
| - Prefer raw string literals for regexes and backslash-heavy path examples to avoid malformed escapes. | ||
| - Before documenting or logging a recommended config value, trace how the consumer uses it. For example, `environmentDirectories` contains directories that hold environments, not environment folders themselves. | ||
|
|
||
| ## Tests Must Prove the Change | ||
|
|
||
| Tests should demonstrate the behavior or performance invariant, not merely execute new lines. | ||
|
|
||
| For optimizations, instrument the dependency boundary and assert the operation count: | ||
|
|
||
| ```rust | ||
| let reads = AtomicUsize::new(0); | ||
| parse_with_reader(path, |_| { | ||
| reads.fetch_add(1, Ordering::Relaxed); | ||
| Some(history.clone()) | ||
| }); | ||
| assert_eq!(reads.load(Ordering::Relaxed), 1); | ||
| ``` | ||
|
|
||
| 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. | ||
|
|
||
| Before every Rust commit, run targeted tests and invoke the `rust-precommit` skill. Keep that skill as the single source of truth for required format and Clippy commands. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.