Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 65 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --check
- run: cargo fmt --all --check

clippy:
runs-on: ubuntu-latest
Expand All @@ -26,18 +26,44 @@ jobs:
components: clippy
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- name: Native
run: cargo clippy --release --all-targets -- -D warnings
- name: Native, all features
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: Native, no features
run: cargo clippy -p eigentrust --all-targets -- -D warnings
- name: WebAssembly
run: cargo clippy --release --target wasm32-unknown-unknown --all-targets -- -D warnings
run: cargo clippy -p eigentrust -p eigentrust-wasm --target wasm32-unknown-unknown --all-targets -- -D warnings

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --release
- name: Every feature combination of the library compiles
run: |
cargo check -p eigentrust --all-targets
cargo check -p eigentrust --all-targets --features csv
cargo check -p eigentrust --all-targets --features parallel
cargo check -p eigentrust --all-targets --all-features
- name: Library without features
run: cargo test -p eigentrust
- name: Workspace, all features (unit, integration and doc tests)
run: cargo test --workspace --all-features
- name: Examples
run: |
cargo run --example basic
cargo run --example csv --features csv

docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- name: Build docs as docs.rs does
run: cargo doc -p eigentrust --all-features --no-deps
env:
RUSTDOCFLAGS: --cfg docsrs -D warnings

wasm:
runs-on: ubuntu-latest
Expand All @@ -59,18 +85,48 @@ jobs:
with:
node-version: 22
- name: Tests in Node
run: wasm-pack test --node --release
run: wasm-pack test --node --release wasm
- name: Single-threaded and multithreaded builds
run: ./build.sh

audit:
package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Package and build the published crates from their tarballs
run: cargo package -p eigentrust -p eigentrust-cli
- name: Library package contents
run: cargo package -p eigentrust --list

dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: taiki-e/install-action@v2
with:
tool: cargo-audit,cargo-machete
- name: Security advisories
run: cargo audit
- name: Unused dependencies
run: cargo machete

# Reports public API changes that need a version bump, compared with main.
# Informational until the first crates.io release; then remove continue-on-error.
semver:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: taiki-e/install-action@v2
with:
tool: cargo-audit
- run: cargo audit
tool: cargo-semver-checks
- run: cargo semver-checks check-release -p eigentrust --baseline-rev origin/${{ github.base_ref }}

attribution:
runs-on: ubuntu-latest
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ firebase.json
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk
Expand Down
52 changes: 31 additions & 21 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,46 @@
- This is enforced by `.githooks/commit-msg` and by CI. Enable the hook once per clone:
`git config core.hooksPath .githooks`
- Never bypass it with `--no-verify`.
- PRs get squash-merged quickly: start follow-up work from a fresh branch off `main`.

## Project

EigenTrust in Rust, runs natively and as WASM in the browser.
EigenTrust in Rust. Cargo workspace:

- `src/basic/engine.rs` - `calculate_from_csv`: CSV in, sorted `(peer, score)` out
- `src/basic/input.rs` - CSV reading (csv crate), header detection, weight validation
- `src/basic/eigentrust.rs` - power iteration (`compute`), runs on dense vectors
- `src/error.rs` - `Error` enum used everywhere; `Display` gives user-facing messages
- `src/sparse/` - CSR matrix / sparse vector
- `src/lib.rs` - wasm-bindgen entry `run(localtrust, pretrust, alpha)` (wasm32 only)
- `src/main.rs` - native CLI, reports errors as `error: ...` with exit code 1
- `demo/` - static interactive web demo deployed to Vercel
- `eigentrust` (root, `src/`) - the library. The only implementation of the algorithm.
- `lib.rs` - crate docs, the public API (`eigentrust`, `eigentrust_with_options`, re-exports)
- `types.rs` (`TrustEdge`, `PreTrust`), `options.rs`, `scores.rs` (`TrustScores`), `error.rs`
- `algorithm/` - private: input validation and normalization (`mod.rs`), CSR matrix,
power iteration (`power.rs`)
- `csv.rs` - `csv` feature: named peers from CSV (`csv::Network`), its own error type
- features: `csv`, `parallel` (rayon); default none
- `eigentrust-cli` (`cli/`) - binary `eigentrust`, uses only the public API
- `eigentrust-wasm` (`wasm/`) - JS bindings; `convert.rs` is plain Rust, `bindings.rs` wasm32 only;
`threads` feature for the multithreaded build; `publish = false`
- `demo/` - static web playground deployed to Vercel

Keep the public surface small: modules private by default, export through `lib.rs`,
`#![warn(missing_docs)]` is on.

## Commands

- Test: `cargo test --release`
- WASM tests: `wasm-pack test --node --release`
- Lint: `cargo fmt --check`, `cargo clippy --release --all-targets -- -D warnings`
(also with `--target wasm32-unknown-unknown`)
- CLI: `cargo run --release -- ./example/localtrust.csv ./example/pretrust.csv [alpha]`
- WASM: `./build.sh` (builds `pkg/` and `pkg-parallel/` and copies them into `demo/`)
- Test: `cargo test --workspace --all-features` (unit, integration, doc tests incl. README)
- Library alone: `cargo test -p eigentrust`
- WASM tests: `wasm-pack test --node --release wasm`
- Lint: `cargo fmt --all --check`, `cargo clippy --workspace --all-targets --all-features -- -D warnings`,
and `cargo clippy -p eigentrust -p eigentrust-wasm --target wasm32-unknown-unknown --all-targets -- -D warnings`
- Docs: `RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo +nightly doc -p eigentrust --all-features --no-deps`
- Package: `cargo package -p eigentrust -p eigentrust-cli`, check `cargo package -p eigentrust --list`
- CLI: `cargo run --release -p eigentrust-cli -- ./example/localtrust.csv ./example/pretrust.csv [alpha]`
- WASM: `./build.sh` (builds `pkg/` and `pkg-parallel/` from `wasm/` and copies them into `demo/`)
- Demo locally: `python3 -m http.server -d demo` then open http://localhost:8000
- Deploy: `vercel deploy --prod` from `demo/`

## Notes

- Tests compare floats with exact equality. The iteration uses Kahan-Babuska-Neumaier summation
in row order; keep the summation order if you touch `compute` / `mul_dense`.
- Duplicate `(i, j)` local trust records and duplicate pre-trust peers: the last one wins.
- Weights must be finite and non-negative. Distrust (negative weights) is rejected until its
effect on the scores is defined; `extract_distrust` / `discount_trust_vector` are kept for that.
- `compute` stops after `DEFAULT_MAX_ITERATIONS` (10,000) with `Error::NotConverged`.
- Results must stay bit-identical: compensated (KBN) sums in a fixed order in `power.rs`, plain
sums for normalization, stable sorts. Tests compare floats exactly.
- Duplicate edges and duplicate pre-trust peers: the last one wins.
- Weights must be finite and non-negative; distrust (negative weights) is rejected.
- The iteration stops after `max_iterations` (default 10,000) with `EigenTrustError::NotConverged`.
- Version 0.2.0 is not on crates.io yet; the CI semver job is informational until it is.
Loading
Loading