Major documentation restructure to improve discoverability and reduce duplication. ## Changes **Deleted (Archived/Consolidated)**: - Removed duplicate getting started guides - Archived outdated planning documents - Consolidated corpus and configuration docs - Removed obsolete vision/spec files (superseded by vision.md) - Cleaned up scrapyard and old PDFs **New Structure**: - docs/about/ - Project overview and introduction - docs/guides/ - User guides (moved from root) - docs/specs/ - Technical specifications - docs/sdk/ - SDK documentation (Go) - docs/references/ - API references - docs/archive/ - Archived historical docs - applications/aphoria/docs/advanced/ - Advanced topics - applications/aphoria/docs/reference/ - CLI reference - applications/aphoria/docs/archive/ - Archived aphoria docs **Updated**: - README.md - New root README with clear navigation - CONTRIBUTING.md - Contribution guidelines - CLAUDE.md - Updated paths to new structure - roadmap.md - Added recent completions ## Files Changed - 57 files changed - 1,977 insertions(+) - 961 deletions(-) **Net change**: +1,016 lines (added CONTRIBUTING.md, README.md, reorganized content) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
146 lines
3.1 KiB
Markdown
146 lines
3.1 KiB
Markdown
# Rust Guidelines for StemeDB
|
|
|
|
**When to use:** Writing Rust code for any StemeDB crate.
|
|
|
|
## Framework
|
|
|
|
All code MUST follow patterns in [Coding Guidelines](../coding-guidelines.md).
|
|
|
|
## Core Principles
|
|
|
|
### 1. Append-Only Everything
|
|
|
|
```rust
|
|
// Good: Append new assertion
|
|
pub fn put(&self, assertion: &Assertion) -> Result<Hash> {
|
|
let hash = assertion.hash();
|
|
self.store.insert(hash.as_bytes(), assertion.to_bytes())?;
|
|
Ok(hash)
|
|
}
|
|
|
|
// Bad: Mutation
|
|
pub fn update(&mut self, hash: &Hash, new_value: Value) {
|
|
// NEVER DO THIS
|
|
}
|
|
```
|
|
|
|
### 2. Content-Addressed Storage
|
|
|
|
```rust
|
|
use blake3::Hasher;
|
|
|
|
impl Assertion {
|
|
pub fn hash(&self) -> Hash {
|
|
let mut hasher = Hasher::new();
|
|
hasher.update(&self.subject.0.as_bytes());
|
|
hasher.update(&self.predicate.0.as_bytes());
|
|
hasher.update(&self.object.to_bytes());
|
|
hasher.update(&self.timestamp.to_le_bytes());
|
|
Hash(hasher.finalize().into())
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Defensive Error Handling
|
|
|
|
```rust
|
|
// Good: Explicit error handling
|
|
pub fn get(&self, hash: &Hash) -> Result<Assertion, StemeError> {
|
|
let bytes = self.store
|
|
.get(hash.as_bytes())
|
|
.context("storage read failed")?
|
|
.ok_or(StemeError::NotFound(*hash))?;
|
|
|
|
rkyv::from_bytes(&bytes)
|
|
.map_err(|e| StemeError::Deserialization(e.to_string()))
|
|
}
|
|
|
|
// Bad: Panic on failure
|
|
pub fn get(&self, hash: &Hash) -> Assertion {
|
|
let bytes = self.store.get(hash.as_bytes()).unwrap().unwrap();
|
|
rkyv::from_bytes(&bytes).unwrap()
|
|
}
|
|
```
|
|
|
|
### 4. Zero-Copy Serialization
|
|
|
|
```rust
|
|
use rkyv::{Archive, Deserialize, Serialize};
|
|
|
|
#[derive(Archive, Deserialize, Serialize)]
|
|
pub struct Assertion {
|
|
pub subject: EntityId,
|
|
pub predicate: RelationId,
|
|
pub object: ObjectValue,
|
|
// ...
|
|
}
|
|
|
|
// Read without copying
|
|
let archived = rkyv::check_archived_root::<Assertion>(&bytes)?;
|
|
println!("Subject: {}", archived.subject.0);
|
|
```
|
|
|
|
## Module Patterns
|
|
|
|
### Public API in lib.rs
|
|
|
|
```rust
|
|
// crates/stemedb-core/src/lib.rs
|
|
|
|
mod assertion;
|
|
mod error;
|
|
mod store;
|
|
mod types;
|
|
|
|
// Re-export public API
|
|
pub use assertion::Assertion;
|
|
pub use error::StemeError;
|
|
pub use store::{Store, MemoryStore};
|
|
pub use types::{EntityId, RelationId, Hash, AgentId, ObjectValue};
|
|
```
|
|
|
|
### Error Types
|
|
|
|
```rust
|
|
// crates/stemedb-core/src/error.rs
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum StemeError {
|
|
#[error("assertion not found: {0:?}")]
|
|
NotFound(Hash),
|
|
|
|
#[error("invalid signature for agent {agent:?}")]
|
|
InvalidSignature { agent: AgentId },
|
|
|
|
#[error("serialization failed: {0}")]
|
|
Serialization(String),
|
|
|
|
#[error("deserialization failed: {0}")]
|
|
Deserialization(String),
|
|
|
|
#[error("storage error: {0}")]
|
|
Storage(#[from] sled::Error),
|
|
}
|
|
|
|
pub type Result<T, E = StemeError> = std::result::Result<T, E>;
|
|
```
|
|
|
|
## Quality Gate
|
|
|
|
Before commit:
|
|
|
|
```bash
|
|
# All must pass
|
|
cargo build --workspace
|
|
cargo test --workspace
|
|
cargo clippy --workspace -- -D warnings
|
|
cargo fmt --check
|
|
```
|
|
|
|
## Related
|
|
|
|
- [Testing Guide](../local/testing.md)
|
|
- [stemedb-core skill](.claude/skills/stemedb-core/SKILL.md)
|
|
- [Architecture](../../../architecture.md)
|