Skip to content

Unify EQBSL and CATHEXIS Rust crates into a shared workspace#22

Open
Copilot wants to merge 4 commits intoimplement-rust-crate-version-of-eqbsl-library-with-docs-examples-and-tests-Wn9PR9JC77fhfrom
copilot/sub-pr-17-again
Open

Unify EQBSL and CATHEXIS Rust crates into a shared workspace#22
Copilot wants to merge 4 commits intoimplement-rust-crate-version-of-eqbsl-library-with-docs-examples-and-tests-Wn9PR9JC77fhfrom
copilot/sub-pr-17-again

Conversation

Copy link
Contributor

Copilot AI commented Mar 13, 2026

This branch had diverged from main in a way that dropped the CATHEXIS Rust crate while introducing a separate EQBSL crate. This update restores the CATHEXIS codepath from main and integrates both Rust codebases as a layered, non-duplicative system: EQBSL as the trust core, CATHEXIS as the semantic trust-handle layer built on top.

  • Workspace + crate topology

    • Added a root Cargo workspace for rust/ and cathexis-rs/
    • Restored cathexis-rs/ and the CATHEXIS manual from main
    • Updated repository docs to describe the two-crate architecture clearly
  • Shared trust core

    • Wired cathexis-rs to depend on the EQBSL crate via eqbsl = { path = "../rust" }
    • Reused the shared EQBSL evidence/opinion mapping instead of keeping a second implementation in CATHEXIS
    • Kept CATHEXIS focused on feature assembly, categorisation, and labeling
  • Integration layer

    • Added a narrow adapter from eqbsl::BasicEmbedding into CATHEXIS TrustEmbedding
    • Preserved CATHEXIS-facing types and APIs while moving shared trust math behind the EQBSL crate boundary
  • Docs + examples

    • Updated the root README and CATHEXIS manual to reflect the layered Rust architecture
    • Clarified that rust/ is the core trust/evidence library and cathexis-rs/ is the higher-level trust-handle pipeline
  • Focused hardening

    • Added small unit tests around CATHEXIS activation helpers, labeling, embedding conversion, and summary construction to pin the integration behavior

Example of the new layering:

# cathexis-rs/Cargo.toml
[dependencies]
eqbsl = { path = "../rust" }
// cathexis-rs/src/core.rs
pub fn to_opinion(&self, base_rate: f64) -> Opinion {
    calculate_opinion(self.r, self.s, self.k, base_rate).into()
}

📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

@superconductor-for-github
Copy link

superconductor-for-github bot commented Mar 13, 2026

✅ @Copilot — Superconductor finishedView implementation


Standing by for instructions.

Copilot AI and others added 2 commits March 13, 2026 12:32
Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Copilot AI changed the title [WIP] [Superconductor Ticket] Implement Rust crate version of EQBSL library Unify EQBSL and CATHEXIS Rust crates into a shared workspace Mar 13, 2026
Copilot AI requested a review from Steake March 13, 2026 12:39
@Steake Steake marked this pull request as ready for review March 13, 2026 12:40
Copilot AI review requested due to automatic review settings March 13, 2026 12:40
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores and integrates the CATHEXIS Rust crate alongside the existing EQBSL Rust crate by introducing a root Cargo workspace and documenting a layered architecture (EQBSL core → CATHEXIS semantic trust-handle layer).

Changes:

  • Added a root Cargo workspace including rust/ (eqbsl) and cathexis-rs/ (cathexis), with updated ignore rules and a consolidated lockfile.
  • Introduced the cathexis-rs crate (pipeline, categoriser, labeling, feature model) wired to the EQBSL core via a path dependency and an embedding adapter.
  • Updated repository documentation to describe and link the two-crate architecture; added basic examples and tests for the CATHEXIS integration surface.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
Cargo.toml Defines the new workspace members (rust, cathexis-rs).
Cargo.lock New workspace lockfile capturing dependency graph for both crates.
.gitignore Ignores workspace-level and per-crate Rust build outputs.
README.md Documents the layered Rust architecture and workspace build/test commands.
rust/README.md Clarifies rust/ as the shared trust core consumed by cathexis-rs.
docs/CATHEXIS-Manual.md Adds CATHEXIS architecture + usage manual.
cathexis-rs/Cargo.toml Adds CATHEXIS crate manifest + dependency on eqbsl via path.
cathexis-rs/README.md Adds crate-level usage and module overview.
cathexis-rs/src/* Implements CATHEXIS pipeline, categoriser, labeling, features, and EQBSL adapter types.
cathexis-rs/examples/basic.rs Adds a runnable demo for the CATHEXIS pipeline.
cathexis-rs/tests/pipeline_test.rs Adds an integration-style test covering the pipeline flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +48 to +70
pub fn batch_process(&mut self) -> Result<(), String> {
let nodes = self.graph.get_nodes();
let mut category_assignments: HashMap<String, usize> = HashMap::new();
let mut category_features: HashMap<usize, Vec<FeatureState>> = HashMap::new();

// 1. Compute features and assign categories
for agent_id in &nodes {
let features = self.graph.compute_features(agent_id)?;
let category_id = self.categoriser.predict(&features)?;

category_assignments.insert(agent_id.clone(), category_id);
category_features.entry(category_id).or_default().push(features);
}

// 2. Build summaries and generate labels
for (category_id, features_list) in category_features {
// Build summary (simplified implementation)
let summary = self.build_category_summary(category_id, &features_list);

// Generate or refresh the current category label from the summary.
let label_info = self.labeler.generate_label(&summary)?;
self.category_labels.insert(category_id, label_info);
}
Comment on lines +80 to +83

// Convert probs to hard category
let category_id = self.categoriser.predict(&features)?;

Comment on lines +12 to +20
fn predict(&self, features: &FeatureState) -> Result<usize, String> {
let probs = self.forward(features)?;
probs
.iter()
.enumerate()
.max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.map(|(index, _)| index)
.ok_or_else(|| "Empty probability vector".to_string())
}
Comment on lines +52 to +55
fn softmax(x: &Array1<f64>) -> Array1<f64> {
let max = x.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
let exp = x.mapv(|v| (v - max).exp());
let sum = exp.sum();
Comment on lines +74 to +81
Self { r, s, k }
}

/// Maps evidence to a Subjective Logic opinion (Equation 3).
/// b = r / (r + s + K)
/// d = s / (r + s + K)
/// u = K / (r + s + K)
pub fn to_opinion(&self, base_rate: f64) -> Opinion {
Comment on lines +10 to +15
serde_json = "1.0"
thiserror = "1.0"
rand = "0.8"
ndarray = { version = "0.15", features = ["serde"] } # Used for categoriser weights, activations, and probability vectors.
uuid = { version = "1.0", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
Comment on lines +49 to +60
let nodes = self.graph.get_nodes();
let mut category_assignments: HashMap<String, usize> = HashMap::new();
let mut category_features: HashMap<usize, Vec<FeatureState>> = HashMap::new();

// 1. Compute features and assign categories
for agent_id in &nodes {
let features = self.graph.compute_features(agent_id)?;
let category_id = self.categoriser.predict(&features)?;

category_assignments.insert(agent_id.clone(), category_id);
category_features.entry(category_id).or_default().push(features);
}
@Steake
Copy link
Owner

Steake commented Mar 13, 2026

@copilot apply changes based on the comments in this thread

Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 13, 2026

@copilot apply changes based on the comments in this thread

Applied all review feedback in commit 29980eb:

  1. pipeline.rs: Clear category_labels at start of batch_process to avoid stale labels
  2. pipeline.rs: Use argmax on probs_array instead of calling predict twice for consistency
  3. pipeline.rs: Remove unused category_assignments variable
  4. categoriser.rs: Handle NaN probabilities in predict by returning an error
  5. categoriser.rs: Validate inputs are finite in softmax and return Result
  6. core.rs: Validate k > 0 and r,s >= 0 in Evidence::new, returning Result
  7. Cargo.toml: Remove unused dependencies (serde_json, thiserror, rand, uuid, chrono)

All 19 workspace tests pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants