docs: Expand EQBSL Rust crate README and update root README with crate details#18
Conversation
|
⏳ Superconductor is working — View implementation I'll get back to you soon! |
Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
|
@copilot Please resolve the issue with the styling of the mermaid diagrams, where background colours mask the text colours. This leads to almost unreadable diagrams. |
Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Fixed in commit c57e95a. Two changes were made to all five diagrams:
|
There was a problem hiding this comment.
Pull request overview
This PR significantly expands the Rust crate README with comprehensive documentation including architecture diagrams, real-world examples, and detailed API reference. The documentation transforms a basic README into a thorough guide with four practical examples (supply chain, DAO voting, AI agent swarm, and P2P lending) and enhanced Mermaid diagrams that are compatible with both light and dark GitHub themes.
Changes:
- Added detailed architecture diagrams using Mermaid (evidence-to-trust pipeline, transitive trust, opinion fusion)
- Included four real-world example implementations with both code and visual diagrams
- Expanded API documentation with detailed function references and parameter explanations
- Added comparison table contrasting EQBSL with traditional trust systems
- Fixed Mermaid diagram styling to ensure text readability in both light and dark themes
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
rust/README.md
Outdated
| A["Alice\n b=0.91, u=0.09\n (veteran, high trust)"] | ||
| B["Bob\n b=0.62, u=0.38\n (active, moderate trust)"] | ||
| C["Carol\n b=0.17, u=0.83\n (new member, high uncertainty)"] | ||
| end | ||
|
|
||
| subgraph Proposal["Proposal: Upgrade Protocol"] | ||
| V["Reputation-Weighted Vote\n weight = b × (1 - u)"] | ||
| end | ||
|
|
||
| A -->|"weight = 0.82"| V | ||
| B -->|"weight = 0.38"| V | ||
| C -->|"weight = 0.03"| V | ||
|
|
||
| V --> R["Result: Passed\n Weighted majority: 0.74"] | ||
|
|
||
| style A fill:#d4edda,stroke:#28a745,color:#000000 | ||
| style C fill:#fff3cd,stroke:#ffc107,color:#000000 | ||
| style R fill:#d1ecf1,stroke:#17a2b8,color:#000000 | ||
| ``` | ||
|
|
||
| ```rust | ||
| use eqbsl::*; | ||
|
|
||
| struct Member { name: String, opinion: Opinion } | ||
|
|
||
| fn dao_voting_example() { | ||
| // Opinions derived from on-chain interaction history | ||
| let members = vec![ | ||
| Member { name: "alice".into(), opinion: calculate_opinion(100.0, 5.0, 2.0, 0.5) }, | ||
| Member { name: "bob".into(), opinion: calculate_opinion(30.0, 3.0, 2.0, 0.5) }, | ||
| Member { name: "carol".into(), opinion: calculate_opinion(2.0, 0.0, 2.0, 0.5) }, | ||
| ]; |
There was a problem hiding this comment.
The opinion values shown in the Mermaid diagram (lines 320-322) don't match the values that would be calculated by the code (lines 347-351).
Diagram shows:
- Alice: b=0.91, u=0.09
- Bob: b=0.62, u=0.38
- Carol: b=0.17, u=0.83
But the code calculates:
- Alice (100, 5): b=100/107=0.935, u=2/107=0.019
- Bob (30, 3): b=30/35=0.857, u=2/35=0.057
- Carol (2, 0): b=2/4=0.5, u=2/4=0.5
Either update the diagram to match the actual calculation results, or adjust the evidence counts in the code to produce the diagram values. For example, to get the diagram values approximately:
- Alice (10, 1): b≈0.833, u≈0.167 (closer to 0.91, 0.09 would need r≈10, s≈0)
- Bob (5, 3): b≈0.5, u≈0.2
- Carol (1, 4): b≈0.143, u≈0.286
|
|
||
| // Coordinator's evidence about peers | ||
| state.edges.insert(("coord".into(), "agent_2".into()), array![12.0, 8.0, 10.0]); | ||
| state.edges.insert(("coord".into(), "agent_3".into()), array![2.0, 9.0, 1.0]); |
There was a problem hiding this comment.
The disbelief value shown in the diagram for Agent-3 (d=0.61) doesn't match the calculation from the evidence counts r=2, s=8.
With r=2, s=8, k=2:
d = 8/(2+8+2) = 8/12 = 0.667 ≈ 0.67
To get d≈0.61, you would need different evidence counts, such as r=1.5, s=6.5, or similar. Either update the diagram to show d=0.67 or adjust the evidence counts in line 426 to match the diagram value.
| state.edges.insert(("coord".into(), "agent_3".into()), array![2.0, 9.0, 1.0]); | |
| state.edges.insert(("coord".into(), "agent_3".into()), array![3.0, 8.0, 1.0]); |
rust/README.md
Outdated
|
|
||
| let mut state = State::new(100); // t=100 (current step) | ||
|
|
||
| // Coordinator's evidence about peers |
There was a problem hiding this comment.
The diagram shows simplified scalar evidence counts (r=12, s=1 for agent_2) while the code uses 3-dimensional evidence vectors with weighted aggregation. This creates a confusing mismatch between what's visualized and what the code actually computes.
For example, the diagram shows agent_2 with r=12, s=1 → b=0.80, but the code uses array![12.0, 8.0, 10.0] which with the given weights produces r≈10.8, s≈11.2 → b≈0.45.
Consider either:
- Updating the diagram to note that values are "conceptual/simplified" and don't reflect the actual multi-channel computation
- Simplifying the code to use scalar evidence that matches the diagram for clarity
- Adding a note explaining the difference between the visualization and implementation
| // Coordinator's evidence about peers | |
| // Coordinator's evidence about peers. | |
| // NOTE: These are 3-channel evidence vectors. The high-level diagram in the docs | |
| // uses simplified scalar r,s counts for illustration, so the numeric values differ. |
rust/README.md
Outdated
| let mut h = std::collections::HashMap::new(); | ||
| h.insert("agent_2".to_string(), "executor".to_string()); | ||
| h.insert("agent_3".to_string(), "executor".to_string()); | ||
| state.hypers.insert("task_42".into(), eqbsl::model::Hyperedge { |
There was a problem hiding this comment.
The code uses eqbsl::model::Hyperedge as a fully qualified path despite having use eqbsl::*; at the top of the example, which already brings Hyperedge into scope via the re-export in lib.rs.
For consistency with the rest of the example code, this should be simplified to just Hyperedge. The current approach works but is unnecessarily verbose.
| state.hypers.insert("task_42".into(), eqbsl::model::Hyperedge { | |
| state.hypers.insert("task_42".into(), Hyperedge { |
rust/README.md
Outdated
| let consensus = members.iter().skip(1).fold(members[0].opinion, |acc, m| acc.fuse(&m.opinion)); | ||
| println!("Consensus opinion: b={:.3}, u={:.3}, E={:.3}", | ||
| consensus.b, consensus.u, consensus.expectation()); | ||
| println!("Proposal {}", if consensus.expectation() > 0.6 { "PASSED" } else { "REJECTED" }); |
There was a problem hiding this comment.
The fusion operation on line 369 computes the consensus of member reputation opinions, but it's not entirely clear what this represents in the context of voting. The weight calculation (lines 354-356) already uses individual opinions, so the fusion result doesn't appear to be used for the voting decision.
Consider clarifying the purpose of the consensus calculation - is it meant to represent the collective reputation of the DAO, or should it be used differently in the voting logic? The current code calculates it but only uses it for display, which might confuse readers about its purpose in the voting mechanism.
rust/README.md
Outdated
| | Sybil resistance | KYC | Introducer trust | **Epistemic uncertainty** | | ||
| | Serializable / portable | Partial | ✗ | **✓ Full serde support** | | ||
|
|
There was a problem hiding this comment.
The comparison table claims EQBSL provides "Epistemic uncertainty" as a form of Sybil resistance, but according to the technical documentation (docs/EQBSL-Primer.md:277), "EQBSL does not provide sybil-resistance; it only provides trust computation over events."
While EQBSL can model uncertainty about new/unknown entities, this is not the same as providing Sybil resistance (preventing an attacker from gaining undue influence by creating multiple identities). The table entry is misleading.
Consider either:
- Changing the entry to "✗" or "Partial" to be more accurate
- Clarifying that uncertainty modeling helps but doesn't constitute true Sybil resistance
- Adding a footnote explaining the distinction
| | Sybil resistance | KYC | Introducer trust | **Epistemic uncertainty** | | |
| | Serializable / portable | Partial | ✗ | **✓ Full serde support** | | |
| | Sybil resistance | KYC | Introducer trust | **Partial† (via uncertainty)** | | |
| | Serializable / portable | Partial | ✗ | **✓ Full serde support** | | |
| † EQBSL itself does not provide Sybil resistance; it only computes trust (opinions) over events. Its explicit modelling of epistemic uncertainty about new or unknown identities can help downstream protocols implement Sybil-resistance policies, but it is not a Sybil-resistance mechanism on its own. |
rust/README.md
Outdated
| P->>L1: Publish anonymised opinion commitment | ||
| P->>L2: Publish anonymised opinion commitment |
There was a problem hiding this comment.
The document uses British English spelling ("anonymised" on lines 482-483, "modelling" on line 549) while the main repository README uses American English spelling ("modeling"). For consistency with the broader codebase, consider using American English spellings: "anonymized" and "modeling".
| P->>L1: Publish anonymised opinion commitment | |
| P->>L2: Publish anonymised opinion commitment | |
| P->>L1: Publish anonymized opinion commitment | |
| P->>L2: Publish anonymized opinion commitment |
rust/README.md
Outdated
| | Feature | Traditional Score | Web-of-Trust | EQBSL | | ||
| |:--------|:-----------------|:-------------|:------| | ||
| | Representation | Scalar (e.g., 4.2 ★) | Boolean | **Tuple (b, d, u, a)** | | ||
| | Uncertainty modelling | ✗ | ✗ | **✓ Explicit via `u`** | |
There was a problem hiding this comment.
The document uses British English spelling "modelling" while the main repository README uses American English "modeling". For consistency with the broader codebase, consider using the American spelling "modeling".
| | Uncertainty modelling | ✗ | ✗ | **✓ Explicit via `u`** | | |
| | Uncertainty modeling | ✗ | ✗ | **✓ Explicit via `u`** | |
|
@copilot apply changes based on the comments in this thread |
…ents Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
All review comments addressed in commit 883d409:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot just FYI please make sure we're consistently using the correct terms - it's "Evidence-Qualified Subjective Logic" |
…Logic Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Fixed in commit 959854f — the |
|
@copilot Merge this |
Merging PRs is outside what I'm able to do — I can only push code changes. You'll need to merge this PR directly on GitHub using the "Merge pull request" button. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| state.hypers.insert("task_42".into(), Hyperedge { | ||
| hid: "task_42".into(), | ||
| nodes: vec!["agent_2".into(), "agent_3".into()], |
rust/README.md
Outdated
| let consensus = members.iter().skip(1).fold(members[0].opinion, |acc, m| acc.fuse(&m.opinion)); | ||
| println!("Consensus opinion: b={:.3}, u={:.3}, E={:.3}", | ||
| consensus.b, consensus.u, consensus.expectation()); | ||
| println!("Proposal {}", if consensus.expectation() > 0.6 { "PASSED" } else { "REJECTED" }); |
rust/README.md
Outdated
|
|
||
| ### `calculate_opinion(r, s, k, a) -> Opinion` | ||
|
|
||
| Maps raw evidence counts to an opinion. Uses `K = DEFAULT_K = 2.0` by default. |
| damping_lambda: 0.7, | ||
| witness_top_k: 5, | ||
| }; | ||
|
|
rust/README.md
Outdated
| // Transitive trust: manufacturer → retailer via distributor | ||
| let nodes = vec!["manufacturer".to_string(), "distributor".to_string(), "retailer".to_string()]; | ||
| let propagated = depth1_propagation_rs(&nodes, &opinions, &state.edges, ¶ms); | ||
| let (r, s) = propagated[&("manufacturer".into(), "retailer".into())]; |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
All five review comments addressed in commit 8aae3e0:
|
|
@copilot OK now update project root README to include the rust crate details too |
Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Done in commit b3ca5de. The root
|
3c1036b
into
implement-rust-crate-version-of-eqbsl-library-with-docs-examples-and-tests-Wn9PR9JC77fh
Expands the Rust crate documentation and updates the project root README to surface the Rust crate alongside the Angular web app.
Changes to
rust/README.mdcolor:#000000on all styled nodes, subgraph fills removed)let (r, s) = propagated[...]to compile-correctlet &(r, s) = propagated.get(...).unwrap()params.validate()call in supply chain examplecalculate_opinionAPI doc wording (no default parameter)docs/EQBSL-Primer.mdanonymised→anonymized,modelling→modelingChanges to root
README.md🦀 Rust Cratesection with feature highlights,Cargo.tomlinstall snippet, quick-start code, and link torust/README.mdrust/directory and its sub-structure💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.