Skip to content

Commit cef28f0

Browse files
jfarcandclaude
andcommitted
docs: comprehensive tutorial updates with SDK and Frontend chapters
New chapters: - Chapter 32: SDK Development Tutorial - Chapter 33: Frontend Development Tutorial Major fixes: - Chapter 11: Restored stdio transport with MCP Sampling support - Chapter 9: Fixed JSON-RPC line number references - Appendix A: Added anyhow prohibition, LazyLock/OnceLock guidance - Appendix B: Complete rewrite matching current CLAUDE.md - Appendix D: Added COROS provider, Recipe Management (7 tools) - Appendix H: Added ProtocolError variants (24 total) Line number updates across 15+ chapters to match current codebase. Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 612ea2c commit cef28f0

23 files changed

+2406
-460
lines changed

src/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
- [SDK CLI Usage](./chapter-29-sdk-cli-usage.md)
5353
- [Performance](./chapter-30-performance.md)
5454
- [Adding New Tools](./chapter-31-adding-new-tools.md)
55+
- [SDK Development](./chapter-32-sdk-development.md)
56+
- [Frontend Development](./chapter-33-frontend-development.md)
5557

5658
# Appendices
5759

src/appendix-a-rust-idioms.md

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,40 @@ let data = fetch_data()?; // Returns early if error
1919
pub struct DbError(String);
2020
```
2121

22+
### Structured Error Types (REQUIRED)
23+
24+
**CRITICAL**: Pierre prohibits `anyhow::anyhow!()` macro in all production code. All errors MUST use structured error types.
25+
26+
**Correct patterns**:
27+
```rust
28+
// GOOD: Using structured error types
29+
return Err(AppError::not_found(format!("User {user_id}")));
30+
return Err(DatabaseError::ConnectionFailed { source: e.to_string() }.into());
31+
32+
// GOOD: Mapping external errors to structured types
33+
external_lib_call().map_err(|e| AppError::internal(format!("API failed: {e}")))?;
34+
35+
// GOOD: Adding context to structured errors
36+
database_operation().context("Failed to fetch user profile")?;
37+
```
38+
39+
**Prohibited patterns (ZERO TOLERANCE)**:
40+
```rust
41+
// ❌ FORBIDDEN: Using anyhow::anyhow!()
42+
return Err(anyhow::anyhow!("User not found"));
43+
44+
// ❌ FORBIDDEN: In map_err closures
45+
.map_err(|e| anyhow!("Failed: {e}"))?;
46+
47+
// ❌ FORBIDDEN: In ok_or_else
48+
.ok_or_else(|| anyhow!("Not found"))?;
49+
```
50+
51+
**Why structured errors?**
52+
- Enable type-safe error handling and proper HTTP status code mapping
53+
- Support better error messages, logging, and debugging
54+
- Make error handling testable and maintainable
55+
2256
## Option and Result Patterns
2357

2458
**`Option::is_some_and`**: Check Some and condition in one call.
@@ -84,12 +118,33 @@ use zeroize::Zeroize;
84118
secret.zeroize(); // Overwrite with zeros
85119
```
86120

87-
**`OnceLock`**: Thread-safe lazy static initialization.
121+
**`LazyLock`**: Thread-safe lazy static initialization (Rust 1.80+, preferred).
88122
```rust
89-
static CONFIG: OnceLock<Config> = OnceLock::new();
90-
CONFIG.get_or_init(|| Config::load());
123+
use std::sync::LazyLock;
124+
125+
// Initialization function runs once on first access
126+
static CONFIG: LazyLock<Config> = LazyLock::new(|| Config::load());
127+
128+
// Usage - always initialized
129+
let cfg = &*CONFIG; // Deref to get &Config
91130
```
92131

132+
**`OnceLock`**: Thread-safe one-time initialization with runtime values.
133+
```rust
134+
use std::sync::OnceLock;
135+
136+
// When you need to set the value dynamically at runtime
137+
static RUNTIME_CONFIG: OnceLock<Config> = OnceLock::new();
138+
139+
fn initialize(config: Config) {
140+
RUNTIME_CONFIG.get_or_init(|| config);
141+
}
142+
```
143+
144+
**When to use which**:
145+
- `LazyLock`: Initialization is known at compile time (replaces `lazy_static!`)
146+
- `OnceLock`: Initialization depends on runtime values or must be deferred
147+
93148
## Memory Allocation Guidance
94149

95150
### When to Use Each Smart Pointer
@@ -224,7 +279,9 @@ let activities_ref = activities.clone(); // Cheap
224279
## Key Takeaways
225280

226281
1. **Error propagation**: Use `?` operator for clean error handling.
227-
2. **Trait objects**: `Arc<dyn Trait>` for shared polymorphism.
228-
3. **Async traits**: `#[async_trait]` macro enables async methods in traits.
229-
4. **Type safety**: Enums and `#[must_use]` prevent common mistakes.
230-
5. **Secure memory**: `zeroize` crate for cryptographic key cleanup.
282+
2. **Structured errors**: `anyhow!()` is forbidden in production code. Use `AppError`, `DatabaseError`, `ProviderError` enums.
283+
3. **Trait objects**: `Arc<dyn Trait>` for shared polymorphism.
284+
4. **Async traits**: `#[async_trait]` macro enables async methods in traits.
285+
5. **Type safety**: Enums and `#[must_use]` prevent common mistakes.
286+
6. **Secure memory**: `zeroize` crate for cryptographic key cleanup.
287+
7. **Lazy statics**: Use `std::sync::LazyLock` (Rust 1.80+) for compile-time-known lazy initialization, `OnceLock` for runtime values.

src/appendix-b-claude-md.md

Lines changed: 215 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,234 @@
11
<!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
22
<!-- Copyright (c) 2025 Pierre Fitness Intelligence -->
33

4-
# Appendix B: CLAUDE.md Compliance Checklist
4+
# Appendix B: CLAUDE.md Compliance Reference
55

6-
Quick checklist for CLAUDE.md code standards compliance.
6+
Comprehensive reference for Pierre codebase standards from `.claude/CLAUDE.md`.
77

88
## Error Handling (Zero Tolerance)
99

10-
- [ ] **No `anyhow::anyhow!()`**: Use `AppError` or specific error types
11-
- [ ] **No `unwrap()`**: Use `?` operator or `unwrap_or`
12-
- [ ] **No `panic!()`**: Return `Result` instead
13-
- [ ] **Structured errors**: Use `thiserror` with named fields
10+
### Structured Error Types (REQUIRED)
1411

15-
## Module Organization
12+
All errors MUST use project-specific error enums:
13+
14+
```rust
15+
// ✅ GOOD: Structured error types
16+
return Err(AppError::not_found(format!("User {user_id}")));
17+
return Err(DatabaseError::ConnectionFailed { source: e.to_string() }.into());
18+
return Err(ProviderError::RateLimitExceeded {
19+
provider: "Strava".to_string(),
20+
retry_after_secs: 3600,
21+
limit_type: "Daily quota".to_string(),
22+
});
23+
24+
// ✅ GOOD: Mapping external errors
25+
external_lib_call().map_err(|e| AppError::internal(format!("API failed: {e}")))?;
26+
```
27+
28+
### Prohibited Patterns (CI Failure)
29+
30+
```rust
31+
// ❌ FORBIDDEN: anyhow::anyhow!()
32+
return Err(anyhow::anyhow!("User not found"));
33+
34+
// ❌ FORBIDDEN: anyhow! macro shorthand
35+
return Err(anyhow!("Invalid input"));
36+
37+
// ❌ FORBIDDEN: In map_err closures
38+
.map_err(|e| anyhow!("Failed: {e}"))?;
39+
40+
// ❌ FORBIDDEN: In ok_or_else
41+
.ok_or_else(|| anyhow!("Not found"))?;
42+
```
43+
44+
### `unwrap()` and `expect()` Rules
45+
46+
- **`unwrap()`**: Only in tests, static data, or binary `main()`
47+
- **`expect()`**: Only for documenting invariants that should never fail:
48+
```rust
49+
// ✅ OK: Static/compile-time data
50+
"127.0.0.1".parse().expect("valid IP literal")
51+
52+
// ❌ FORBIDDEN: Runtime errors
53+
user_input.parse().expect("should be valid") // NO!
54+
```
55+
56+
## Code Style Requirements
57+
58+
### File Headers (REQUIRED)
59+
60+
All code files MUST start with ABOUTME comments:
61+
62+
```rust
63+
// ABOUTME: Brief description of what this module does
64+
// ABOUTME: Additional context about the module's responsibility
65+
```
66+
67+
### Import Style (Enforced by Clippy)
68+
69+
Use `use` imports at the top of the file. Avoid inline qualified paths:
70+
71+
```rust
72+
// ✅ GOOD: Import at top of file
73+
use crate::models::User;
74+
use std::collections::HashMap;
75+
76+
fn example() {
77+
let user = User::new();
78+
let map = HashMap::new();
79+
}
80+
81+
// ❌ BAD: Inline qualified paths
82+
fn example() {
83+
let user = crate::models::User::new(); // NO!
84+
let map = std::collections::HashMap::new(); // NO!
85+
}
86+
```
87+
88+
### Naming Conventions
89+
90+
- **NEVER** use `_` prefix for unused variables (fix the unused variable properly)
91+
- **NEVER** name things `improved`, `new`, `enhanced` - code naming should be evergreen
92+
- **NEVER** add placeholder, `dead_code`, or mock code in production
93+
94+
### Comments
1695

17-
- [ ] **Public API in mod.rs**: Re-export public items
18-
- [ ] **Private implementation**: Keep internals private
19-
- [ ] **Logical grouping**: Related functionality in same module
20-
- [ ] **Feature flags**: Conditional compilation for database backends
96+
- **NEVER** remove existing comments unless provably false
97+
- Comments should be evergreen - avoid temporal references ("after refactor", "recently changed")
98+
- Use `///` for public API documentation
99+
- Use `//` for inline implementation comments
21100

22-
## Documentation
101+
## Tiered Validation Approach
23102

24-
- [ ] **Doc comments**: `///` for public items
25-
- [ ] **Examples**: Include usage examples in doc comments
26-
- [ ] **Error cases**: Document when functions return errors
27-
- [ ] **Safety**: Document `unsafe` code (if unavoidable)
103+
### Tier 1: Quick Iteration (during development)
28104

29-
## Testing
105+
```bash
106+
cargo fmt
107+
cargo check --quiet
108+
cargo test <test_name_pattern> -- --nocapture
109+
```
30110

31-
- [ ] **Unit tests**: Test individual functions
32-
- [ ] **Integration tests**: Test component interaction
33-
- [ ] **Deterministic**: Use seeded RNG for reproducible tests
34-
- [ ] **No external dependencies**: Use synthetic data, not OAuth
111+
### Tier 2: Pre-Commit (before committing)
35112

36-
## Security
113+
```bash
114+
cargo fmt
115+
./scripts/architectural-validation.sh
116+
cargo clippy --all-targets -- -D warnings -D clippy::all -D clippy::pedantic -D clippy::nursery -W clippy::cognitive_complexity
117+
cargo test <module_pattern> -- --nocapture
118+
```
37119

38-
- [ ] **Input validation**: Validate all user inputs
39-
- [ ] **SQL injection prevention**: Use parameterized queries
40-
- [ ] **Secret management**: Never hardcode secrets
41-
- [ ] **Secure memory**: `zeroize` for cryptographic keys
120+
**CRITICAL**: Always use `--all-targets` with clippy. Without it, clippy misses lint errors in `tests/`, `benches/`, and binary crates.
42121

43-
## Performance
122+
### Tier 3: Full Validation (before PR/merge)
44123

45-
- [ ] **Database pooling**: Reuse connections
46-
- [ ] **Async operations**: Use `tokio` for I/O
47-
- [ ] **Minimal cloning**: Only clone when necessary
48-
- [ ] **Efficient algorithms**: Use appropriate data structures
124+
```bash
125+
./scripts/lint-and-test.sh
126+
```
49127

50-
## Key Takeaways
128+
Full test suite takes ~13 minutes (647 tests). Only run for PRs/merges.
129+
130+
## Memory and Performance
131+
132+
### Clone Usage Guidelines
133+
134+
Document why each `clone()` is necessary:
135+
136+
```rust
137+
// ✅ OK: Arc clone (cheap, self-documenting)
138+
let db_clone = database.clone();
139+
140+
// ✅ OK: Documented clone
141+
let name = user.name.clone(); // Needed: ownership moves to async task
142+
tokio::spawn(async move {
143+
process(name).await;
144+
});
145+
146+
// ❌ BAD: Unnecessary clone
147+
let name = user.name.clone();
148+
println!("{}", name); // Should just use &user.name
149+
```
150+
151+
### Arc Usage
152+
153+
- Only use when actual shared ownership required across threads
154+
- Document the sharing requirement in comments
155+
- Prefer `&T` references when data lifetime allows
156+
- Current count: ~107 Arc usages (appropriate for multi-tenant async architecture)
157+
158+
### Lazy Statics
159+
160+
```rust
161+
// ✅ GOOD: LazyLock for compile-time-known initialization (Rust 1.80+)
162+
use std::sync::LazyLock;
163+
static CONFIG: LazyLock<Config> = LazyLock::new(|| Config::load());
164+
165+
// ✅ GOOD: OnceLock for runtime values
166+
use std::sync::OnceLock;
167+
static RUNTIME_CONFIG: OnceLock<Config> = OnceLock::new();
168+
```
169+
170+
## Testing Requirements
171+
172+
### Test Coverage Policy
173+
174+
NO EXCEPTIONS: All code must have:
175+
- Unit tests
176+
- Integration tests
177+
- End-to-end tests
178+
179+
Only skip with explicit authorization: "I AUTHORIZE YOU TO SKIP WRITING TESTS THIS TIME"
180+
181+
### Test Targeting
182+
183+
```bash
184+
# By test name (partial match)
185+
cargo test test_training_load
186+
187+
# By test file
188+
cargo test --test intelligence_test
189+
190+
# By module path
191+
cargo test intelligence::
192+
```
193+
194+
## Security Requirements
195+
196+
- **Input validation**: Validate all user inputs at boundaries
197+
- **SQL injection prevention**: Use parameterized queries
198+
- **Secret management**: Never hardcode secrets, use `zeroize` for crypto keys
199+
- **No `allow(clippy::...)` attributes** except for type conversion casts
200+
201+
## Module Organization
51202

52-
1. **Error handling**: Zero tolerance for `anyhow::anyhow!()` and `unwrap()`.
53-
2. **Module organization**: Clear public API, private internals.
54-
3. **Documentation**: Comprehensive doc comments with examples.
55-
4. **Testing**: Deterministic tests with synthetic data.
56-
5. **Security**: Input validation, parameterized queries, secret management.
203+
- Public API defined in `mod.rs` via re-exports
204+
- Use `pub(crate)` for internal APIs
205+
- Group related functionality in modules
206+
- Feature flags for conditional compilation (database backends)
207+
208+
## Commit Protocol
209+
210+
1. Run tiered validation (Tier 2 minimum)
211+
2. Create atomic commits with clear messages
212+
3. **NEVER** use `--no-verify` flag
213+
4. **NEVER** amend commits already pushed to remote
214+
215+
## Key Compliance Checks
216+
217+
| Check | Requirement |
218+
|-------|-------------|
219+
| `anyhow!()` macro | ❌ FORBIDDEN in production code |
220+
| `unwrap()` | Tests/static data/binary main only |
221+
| `#[allow(clippy::...)]` | Only for cast validations |
222+
| ABOUTME comments | REQUIRED on all source files |
223+
| `--all-targets` | REQUIRED with clippy |
224+
| Structured errors | REQUIRED via `AppError`, etc. |
225+
226+
## Quick Checklist
227+
228+
- [ ] No `anyhow::anyhow!()` in production code
229+
- [ ] No unwarranted `unwrap()` or `expect()`
230+
- [ ] ABOUTME comments at top of file
231+
- [ ] Use imports, not inline qualified paths
232+
- [ ] Document `clone()` usage when not Arc
233+
- [ ] Run clippy with `--all-targets`
234+
- [ ] Tests for all new functionality

0 commit comments

Comments
 (0)