Skip to content

Latest commit

 

History

History
634 lines (462 loc) · 31.5 KB

AGENTS.md

File metadata and controls

634 lines (462 loc) · 31.5 KB

deep_causality Codebase Guide for Agents

Core Directives

Communication Style:

Direct and Unfiltered: Do not use polite fillers or "I'm sorry". Just state the truth as it is.

Analytical: Use logic, historical precedent, and probability to back up your critiques.

Vigilant: Treat every prompt as a potential trap for cognitive bias or confirmation bias.

Tone: Be respectful regardless of agreement. Its okay to disagree, correct, and call out as long as its respectful.

Golden Rules

  1. Never ever git commit. Prepare a commit message and ask the user to commit.
  2. Never ever delete files or folders. Ask the user for permission.

file mv and git mv (preserves history) is generally authorized.

Behavioral Guidelines

These guidelines favor correctness, clarity, and minimal diffs over speed. For trivial tasks, use judgment.

  1. check claims against the tree before writing them into docs or specs
  2. document what the code does, not its history or justification;
  3. a negative control that returns zero may mean the control is miscalibrated,

1. Think Before You Code

Do not silently guess.

Before making changes:

  • State your assumptions clearly.

  • If anything is ambiguous, ask instead of choosing one interpretation silently.

  • If there are multiple valid approaches, briefly present the tradeoff.

  • If the request seems mistaken, inefficient, or overcomplicated, say so.

  • If a simpler solution exists, recommend it before implementing.

  • If you are confused, stop and explain what is unclear.

  • Do not act certain when you are uncertain.

2. Keep the Solution Simple

Solve the requested

problem with the minimum necessary code.

  • Do not add features that were not asked for.
  • Do not introduce abstractions for one-time
  • Do not add configurability, extensibility, or generalization unless requested.
  • Do not add defensive error handling for unrealistic cases.
  • Prefer simple, readable code over clever code.
  • If the solution feels too large, step back and simplify it.

Ask yourself:

  • Is this the smallest change that solves the problem?

  • Would a senior engineer consider this unnecessarily complex?

  • If yes, simplify.

3. Stay Strictly Within Scope

Only change what the task requires.

When editing existing code:

  • Do not refactor unrelated code.
  • Do not rewrite comments, formatting, or naming unless necessary for the task.
  • Match the existing style and conventions of the codebase.
  • Do not fix neighboring issues unless the user asked.
  • If you notice unrelated problems, mention them separately instead of changing them.

Every changed line should be easy to justify from the request.

4. Make Surgical Diffs

Keep edits local, focused, and easy to review.

  • Touch as few files as possible.
  • Change as little code as necessary.
  • Avoid broad rewrites when a targeted fix is enough.
  • Prserve existing structure unless changing it is required.
  • Remove only the dead code, imports, or variables created by your own changes.
  • Do not delete pre-existing unused code unless asked.

Prefer small and focused diffs over sweeping cleanup.

5. Work Toward Verifiable Outcomes

Do not treat "done" as a guess.

Turn requests into clear success criteria whenever possible.

  • "Fix the bug" - reproduce it, fix it, then verify the fix
  • "Add validation" -> add checks for invalid input and verify behavior
  • "Refactor this" - preserve behavior and confirm tests still pass
  • "Optimize this" -> improve performance without changing correctness For multi-step tasks, make a short plan with verification points.

Examples:

  1. Inspect the current behavior -> verify: identify the root cause of the issue
  2. Implement the minimal fix -> verify: affected behavior changes as expected
  3. Run tests or checks -> verify: no regressions introduced

Prefer tests, existing checks, or concrete validation over verbal confidence.

6. Read Before You Write

Understand the surrounding code before editing it.

  • Read enough nearby code to understand how the target piece fits in.
  • Identify the local conventions before introducing new patterns.
  • Do not infer architecture from one file when other relevant files are available.
  • If context is missing, say so.

Understand the existing layers of abstraction:

  • Identify the various levels of abstraction in the affected codebase.
  • Expand the search of the codebase to understand the various levels of abstraction already in place.
  • Ensure that new code lands at the right level of abstraction in the existing code base.
  • If you find inconsistencies of abstraction, flag them. Stop and say so.
  • If you cannot determine where to put new code in the abstraction hierarchy, flag, stop and say so.

Do not patch blindly.

7. Preserve Intent

Do not accidentally erase meaning while making changes.

  • Preserve comments unless they are clearly outdated and directly affected by the task.
  • Preserve behavior unless the requested change is meant to alter it.
  • Preserve public interfaces unless changing them is necessary.
  • Call out any intentional behavior change explicitly.

Do not make hidden product or design decisions on the user's behalf. Instead, ask.

8. Ask for Help at the Right Time

Do not continue blindly when the risk is high.

Pause and ask if:

  • the request is ambiguous in a way that affects implementation
  • the codebase contains conflicting patterns
  • the correct behavior is unclear
  • the task requires a product or architectural decision
  • you are choosing between tradeoffs the user should approve

Do not fabricate certainty to stay moving.

9. Final Check Before You Finish

Before considering the task complete, confirm:

  • the request was actually addressed
  • the change is no larger than necessary
  • unrelated code was not modified
  • assumptions were surfaced
  • affected tests or checks were run when possible
  • the final result matches the requested scope

If something could not be verified, say that clearly.

Project Overview

This project, deep_causality, is a Rust-based monorepo for a computational causality library. It enables fast, context-aware causal reasoning over complex multi-stage causality models. The library is designed for dynamic systems where time is not linear, causal rules can change, and context is dynamic.

The core of the library is built on the idea of "Causality is a spacetime-agnostic functional dependency." It uses three main components:

  • Causaloid: A self-contained unit of causality.
  • Context: An explicit environment (a hypergraph) where Causaloids operate.
  • Effect Ethos: A programmable layer for verifying operational rules.

Project Structure

The project is a monorepo containing 33 library crates.

Directory layout

Twelve crates sit at the repository root. The seventeen mathematics crates live under deep_causality_unified_math/ and the four utility crates under deep_causality_utils/, one directory per crate:

deep_causality_unified_math/deep_causality_{algebra, calculus, fft, haft, homology,
                                            linear, metric, multivector, num, num_complex,
                                            num_dual, num_rational, rand, stats, tensor,
                                            topology, uncertain}

deep_causality_utils/deep_causality_{ast, file, par, tempfile}

Package names are unchanged, so every use statement, every cargo -p <name> and every crates.io entry reads exactly as before. Only paths moved: a Cargo path dependency into one of the seventeen is ../deep_causality_unified_math/deep_causality_x and into one of the four is ../deep_causality_utils/deep_causality_x; the Bazel labels are //deep_causality_unified_math/deep_causality_x and //deep_causality_utils/deep_causality_x. The crates that stayed at the root are deep_causality, _algorithms, _cfd, _context, _context_store, _core, _data_structures, _discovery, _ethos, _physics, _quantum and ultragraph.

The groupings below are conceptual and cut across that split: metric is filed under Core, haft under Functional Programming, and homology and topology under Topology and Physics, but all four live in deep_causality_unified_math/. ast, file, par and tempfile are filed under Core and Data Structures but live in deep_causality_utils/: none of the four is mathematics. ast, file and par are each used by crates on both sides of the split; tempfile is a test-only dependency.

Core Crates

  • deep_causality: Computational causality library. Provides causality graph, collections, context and causal reasoning.
  • deep_causality_context: The context layer — the Context hypergraph, its contextoids, the context node types (data, space, time, spacetime) and the contextuable traits. Separate from deep_causality so context is an opt-in dependency: reasoning without context costs nothing, and a model that needs context declares this crate. Persists through deep_causality_context_store: Storable, ContextStore, Context::snapshot, restore and apply.
  • deep_causality_context_store: The persistence contract for the context — the records a Context projects onto, the ContextStorage trait a backend implements, the optional ContextStorageStream and Substrate traits, and an in-memory backend under utils_test. No dependencies, so a backend links this crate alone.
  • deep_causality_core: Core types for the deep_causality crate.
  • deep_causality_ast: AST data structure for the deep_causality crate.
  • deep_causality_metric: Foundational metric signatures used acros tensor, multivector, and physics.
  • deep_causality_par: Shared parallelism primitives (the MaybeParallel marker) used across the compute crates.

Data Structure Crates

  • deep_causality_data_structures: Data structures for deep_causality (sliding-window, grid-array).
  • deep_causality_file: File and receiver-data (RINEX GNSS SP3/CLK) loaders over the haft IO monad.
  • deep_causality_tempfile: Scratch files and directories removed on drop, std only. No dependencies; the test suites use it for temporary paths.
  • ultragraph: Hypergraph data structure used as a backend in deep_causality.

Algorithm and Discovery Crates

  • deep_causality_algorithms: Computational causality algorithms (SURD, MRMR) and utils.
  • deep_causality_discovery: Causality discovery DSL for the DeepCausality project.

Math and Numerics Crates

  • deep_causality_algebra: Abstract algebra traits (groups, rings, fields, algebras) and isomorphism markers.
  • deep_causality_calculus: "Arrow-native differentiation and integration operators.
  • deep_causality_fft: Fast Fourier transform (FFT, rFFT, N-dimensional).
  • deep_causality_num: Numerical traits and utils (casts, identity, float, integer) used across all crates.
  • deep_causality_num_complex: Complex, quaternion, and octonion number types.
  • deep_causality_num_dual: Dual number type (forward-mode automatic differentiation).
  • deep_causality_num_rational: Exact rational number type over the integers.
  • deep_causality_rand: Entropy — generators, the word and Boolean draws, range sampling, Sobol. States no distribution.
  • deep_causality_stats: Statistical distributions, densities, moments and estimators.
  • deep_causality_linear: Linear algebra — sparse (CSR), dense and bit-packed 𝔽₂ matrices, vectors, eliminations, decompositions, conjugate gradient, and an exact integer path.
  • deep_causality_tensor: N-index tensors, broadcasting, Einstein summation, and the tensor-train stack. Its rank-2 decompositions delegate to deep_causality_linear.
  • deep_causality_multivector: Multivector implementation for geometric algebra.
  • deep_causality_uncertain: A first-order type for uncertain programming.

Functional Programming Crates

  • deep_causality_haft: Higher-Order Abstract Functional Traits (HKT).
  • deep_causality_ethos: Programmable ethics for DeepCausality.

Topology and Physics Crates

  • deep_causality_homology: Chain complexes, boundary operators, and homology over a chosen coefficient field. No geometry: a quantum code is a chain complex with no cells.
  • deep_causality_topology: Topological data structures (complexes, manifolds, differential geometry).
  • deep_causality_physics: Standard library of physics formulas and engineering primitives.
  • deep_causality_quantum: Quantum types — density matrices, channels, gates — over the complex tower.
  • deep_causality_cfd: Computational fluid dynamics solvers and the Flow DSL.

Project Dependencies

Scope: the 33 library crates that are workspace members. Example crates (examples/*) and yanked/* are excluded. Third-party crates are resolved from the registry by rules_rs into @crates; there is no vendored source tree. deep_causality_effects, deep_causality_macros and deep_causality_sparse were moved to yanked/ and are no longer workspace members, so all three are omitted. deep_causality_sparse was a re-export shim over deep_causality_linear; 0.2.5 is its last crates.io release.

The tier block below is derived from the [dependencies] tables of each member's Cargo.toml, dev- and build-dependencies excluded. scripts/crates.sh reads the same source for the build scripts, so a crate added to the workspace appears in both without an edit here. After adding a crate or changing a dependency, re-derive the tiers from the Cargo.toml files and update this block and the tier block in deep_causality_unified_math/README.md by hand. deep_causality_cfd was released to crates.io as 0.1.0 on 2026-08-12.

Internal Dependencies

Crates are arranged in dependency tiers: a crate depends only on crates in lower tiers. → lists the direct internal (path) dependencies. (opt) marks an optional, feature-gated dependency. Dev/test/bench-only dependencies are shown separately below.

Tier 0 — Foundational (no internal runtime dependencies)
  deep_causality_ast
  deep_causality_context_store
  deep_causality_data_structures
  deep_causality_metric
  deep_causality_num
  deep_causality_par
  deep_causality_tempfile
  ultragraph

Tier 1
  deep_causality_algebra      → deep_causality_num

Tier 2
  deep_causality_haft         → deep_causality_algebra
  deep_causality_num_rational → deep_causality_algebra, deep_causality_num
  deep_causality_rand         → deep_causality_algebra, deep_causality_num

Tier 3
  deep_causality_core         → deep_causality_haft
  deep_causality_file         → deep_causality_algebra, deep_causality_haft, deep_causality_num
  deep_causality_linear       → deep_causality_algebra, deep_causality_haft, deep_causality_num
  deep_causality_num_complex  → deep_causality_algebra, deep_causality_haft, deep_causality_num
  deep_causality_num_dual     → deep_causality_algebra, deep_causality_haft, deep_causality_num

Tier 4
  deep_causality_calculus     → deep_causality_algebra, deep_causality_haft, deep_causality_num,
                                deep_causality_num_dual
  deep_causality_fft          → deep_causality_algebra, deep_causality_num,
                                deep_causality_num_complex, deep_causality_par
  deep_causality_homology     → deep_causality_linear, deep_causality_num
  deep_causality_stats        → deep_causality_algebra, deep_causality_linear, deep_causality_num,
                                deep_causality_rand

Tier 5
  deep_causality_tensor       → deep_causality_algebra, deep_causality_ast, deep_causality_haft,
                                deep_causality_linear, deep_causality_num,
                                deep_causality_num_complex, deep_causality_num_dual,
                                deep_causality_stats
  deep_causality_uncertain    → deep_causality_algebra, deep_causality_ast, deep_causality_haft,
                                deep_causality_num, deep_causality_rand, deep_causality_stats

Tier 6
  deep_causality_context      → deep_causality_algebra, deep_causality_context_store,
                                deep_causality_core, deep_causality_data_structures,
                                deep_causality_metric, deep_causality_num, deep_causality_uncertain,
                                ultragraph
  deep_causality_multivector  → deep_causality_algebra, deep_causality_haft, deep_causality_linear,
                                deep_causality_metric, deep_causality_num,
                                deep_causality_num_complex, deep_causality_tensor

Tier 7
  deep_causality              → deep_causality_algebra, deep_causality_ast, deep_causality_context,
                                deep_causality_core, deep_causality_data_structures,
                                deep_causality_haft, deep_causality_uncertain, ultragraph
  deep_causality_topology     → deep_causality_algebra, deep_causality_fft, deep_causality_haft,
                                deep_causality_homology, deep_causality_linear,
                                deep_causality_metric, deep_causality_multivector,
                                deep_causality_num, deep_causality_num_complex, deep_causality_par,
                                deep_causality_stats, deep_causality_tensor

Tier 8
  deep_causality_algorithms   → deep_causality_algebra, deep_causality_linear, deep_causality_num,
                                deep_causality_par, deep_causality_rand, deep_causality_stats,
                                deep_causality_tensor, deep_causality_topology (opt)
  deep_causality_ethos        → deep_causality, deep_causality_context, ultragraph
  deep_causality_physics      → deep_causality_algebra, deep_causality_calculus,
                                deep_causality_core, deep_causality_haft, deep_causality_linear,
                                deep_causality_metric, deep_causality_multivector,
                                deep_causality_num, deep_causality_num_complex,
                                deep_causality_num_dual, deep_causality_par, deep_causality_rand
                                (opt), deep_causality_stats, deep_causality_tensor,
                                deep_causality_topology (opt)
  deep_causality_quantum      → deep_causality (opt), deep_causality_algebra,
                                deep_causality_context (opt), deep_causality_context_store (opt),
                                deep_causality_core, deep_causality_haft, deep_causality_homology,
                                deep_causality_linear, deep_causality_metric,
                                deep_causality_multivector, deep_causality_num,
                                deep_causality_num_complex, deep_causality_num_rational,
                                deep_causality_stats, deep_causality_tensor,
                                deep_causality_uncertain (opt)

Tier 9
  deep_causality_cfd          → deep_causality_algebra, deep_causality_calculus,
                                deep_causality_core, deep_causality_fft, deep_causality_file,
                                deep_causality_haft, deep_causality_linear, deep_causality_num,
                                deep_causality_num_complex, deep_causality_num_dual,
                                deep_causality_par, deep_causality_physics, deep_causality_tensor,
                                deep_causality_topology, deep_causality_uncertain (opt)
  deep_causality_discovery    → deep_causality_algebra, deep_causality_algorithms,
                                deep_causality_haft, deep_causality_num, deep_causality_par,
                                deep_causality_stats, deep_causality_tensor, deep_causality_topology

Internal dev-only dependency (tests/benches, not part of any published runtime):

  • deep_causality_rand is a dev-dependency of deep_causality_data_structures, deep_causality_discovery, deep_causality_tensor, and ultragraph.
  • deep_causality_num_complex and deep_causality_num_rational are dev-dependencies of deep_causality_linear.
  • deep_causality_topology is a dev-dependency of deep_causality_quantum.
  • deep_causality_tempfile is a dev-dependency of deep_causality_cfd, deep_causality_discovery and deep_causality_file.

External Dependencies

Only crates with at least one external (crates.io) runtime dependency are listed. The other 26 library crates have no external runtime dependencies.

Crate External dependency Status
deep_causality_num libm optional — libm_math / no-std feature
deep_causality_rand getrandom optional — os-random feature
deep_causality_algorithms rayon optional — parallel feature
deep_causality_fft rayon optional — parallel feature
deep_causality_topology rayon optional — parallel feature
deep_causality_discovery csv, parquet required (runtime)
deep_causality_file chrono required (runtime)

External dev-only dependencies (tests/benches, not part of any published runtime):

  • criterion — benchmarks in deep_causality, deep_causality_algorithms, deep_causality_cfd, deep_causality_data_structures, deep_causality_fft, deep_causality_multivector, deep_causality_tensor, deep_causality_uncertain, ultragraph.
  • rusty-fork — deep_causality_uncertain tests.

Building and Running

The project uses make to simplify the execution of common development tasks. The makefile in the root of the project defines the following commands:

  • make build: Builds the entire mono-repo
  • make test: Tests the entire mono-repo (Slow)
  • make fix: Fixes linting issues as reported by clippy.
  • make format: Formats all code according to the cargo fmt style.
  • make check: Checks the code base for security vulnerabilities.

Development Conventions

Building and testing a specific crate is preferred over building the entire project. Use the following commands by default.

cargo build -p crate_name

cargo test -p crate_name

After a major code change, format and lint the entire code base:

make format && make fix

Only when multiple crate (3 or more) have changed at once, you run:

make format && make fix Format and fix lints

make build: Builds the entire mono-repo

make test: Tests the entire mono-repo

To rebuild and test the entire repo

Code documentation

  1. Document what the code does; never its history or justification;
  2. Use clear and exact language
  3. Verify each statement against the actual code
  4. Explain only non-obvios aspects or decisions.
  5. Keep it conscise, and correct.

Code testing

You aim for one hundred percent test coverage of all added or edited code files. The only exception is if, for some reason, some code is impossible to reach. Then you skip testing that dead code.

Coverage is a floor

Coverage says a line ran. It does not say a test would notice if that line were wrong, and the two come apart on exactly the code that matters most.

The topological-charge normalization in deep_causality_topology was eight times too small. The line computing it ran 513 times across the suite. Every test of it used the identity gauge field, where the field strength is zero, so q == 0 held for any constant whatsoever. Four true assertions, full coverage, and a wrong answer that survived until someone compared the docstring with the code.

That failure has a shape, and it recurs: a test that pins a quantity only where the quantity vanishes, or only at one well-behaved input. Watch for it when a test

  • asserts a result is zero, and the suspected error is a factor or an offset,
  • uses only the identity, a diagonal, or a symmetric matrix, where several distinct quantities coincide,
  • uses only one size, where an index expression degenerates. A 2x2 Cholesky has one off-diagonal entry at j = 0, and there a[i * n + j] and a[i * n - j] are the same number.

Mutation testing

scripts/mutants.sh runs cargo mutants, which changes one expression at a time and re-runs the tests. A mutant no test objects to is a decision nothing pins. It answers the question coverage cannot.

Point it at code where a wrong constant or a flipped comparison yields a plausible number rather than a crash: numeric kernels, tolerance gates, index arithmetic. It is not a whole-workspace gate, because every mutant costs a build plus a test run and deep_causality_unified_math/deep_causality_linear/src/algorithms alone yields 1156 of them.

Equivalent mutants — changes that cannot alter behaviour — belong in .cargo/mutants.toml, each with the measurement that settles it rather than an assertion that it is fine. A survivor not listed there is a real gap.

Those entries are regular expressions matched against text that is itself full of regex metacharacters, and getting one wrong is silent both ways: an unescaped + or * matches nothing, an unescaped || matches everything, and cargo mutants reports neither. Escape them, and confirm the entry did what it claims with the comm check the file carries.

An entry must also match no more than it argues for, which the same check shows. A pattern like replace + with * in <function> reads as one mutation and matches every + in that function, index arithmetic included. Two such entries once hid 32 mutants the suite was killing in order to excuse 5 it could not. Prefer a pattern that resolves to a single mutant; where none exists, describe the equivalence in prose and leave the mutant in the report.

Code examples under examples/* are exempt from the coverage requirement. They are runnable demonstrations, not library code, and are verified by running them (cargo run -p <crate> --example <name>, or bazel run //examples/<package>:<name>) rather than by unit tests. Do not add test files or test modules for example binaries.

Every [[example]] also needs a rust_binary in its owning package's BUILD.bazel, because Bazel does not read Cargo.toml. Two places declare examples: the packages under examples/, and the library crates carrying their own verification harnesses and studies (deep_causality_cfd/verification and studies, deep_causality_algorithms/verification, and others). In a library crate the example binaries sit below the rust_library under a # Example binaries comment and depend on :<crate_name>. A binary's deps list the crates that example's own sources reference, not the package-wide Cargo dependency set.

make check_examples fails when a Cargo example has no Bazel target, across both locations. An example that is deliberately Cargo-only is listed in scripts/check_examples.sh with the reason recorded in the owning package's BUILD.bazel.

An example that reads bundled data or records an output table resolves the path through a manifest_dir() helper rather than env!("CARGO_MANIFEST_DIR"). Under Bazel the compile-time manifest directory names a rustc sandbox that no longer exists when the binary runs, so the helper falls back to it only under Cargo and uses BUILD_WORKSPACE_DIRECTORY under bazel run. The helper lives in the example package's own lib (paths::manifest_dir()), or, for a library crate, in the shared example module next to the harnesses (deep_causality_algorithms/verification/brcd/common.rs) so it stays out of the published src/.

If tests find any bug, you fix the implementation so that the test pass. Because the testing exists to ensure that the API is correct, and if the API is not correct, you fix the API so that the test is passing.

Never ever fix any test to make a broken or incorrect API pass a bogus test. Never.

If you encounter a severe bug that requires refactoring beyond the first level implementation, and you suspect a large blast radius of breaking changes, ask the user how to proceed.

If you can derive a cleaner or better architecture, please do so and refactor downstream tests. This is okay. However, do not compromise any architecture for test compatibility, because remember, test exists to decide if the API is correct or not. If the API changes, so do the tests to veify that the new architectue is correct.

Code structure

Each crate adheres to the following base structure

src/errors/mod.rs # contains each error type in a separate file src/traits/mod.rs # contains each trait in a separate file src/type/mod.rs # contains each type in a separate file

One type, one Rust module.

For very small types (total implementation in less than 25 lines), the type is stored in file named as snail_case of the type name. For example:

src/types/small_type.rs

For more complex types, the type is stored a folder module for example, the type Uncertain is stored in:

src/types/uncertain/mod.rs

The mod.rs contains the type definition and constructors.

When the type implements multiple traits, each trait is stored within a file named after the implementing trait or trait group. For example, when implementing PartialEq and Debug for type Uncertain, these would be in files:

src/types/uncertain/uncertain_debug.rs src/types/uncertain/uncertain_part_eq.rs

Optional src folders

src/extensions/mod.rs # contains type extensions i.e. a default impl for a trait src/utils/mod.rs # contains utils

One notable exception is the deep_causality_num crate that uses a different structure due to the particularities of modelling numerical properties in Rust.

Test structure

Every single test files must be registered to the correspoding mod file and that module must be registered with its higher up module. ensure the corrext #[cfg(test)] annotation is set for each registeres test file.

Also, ensure the folder modules are correctly declared in the Bazel configration undre crate_name/BUILD.bazel.

The tests folder replicates the exact src folder structure, for for example:

tests/errors/mod.r # contains tests for each error type in a separate file tests/traits/mod.rs # Optional contains tests for each trait in a separate file tests/type/mod.rs # contains tests for each type in a separate file

Test files replicate the source file name with an appended _tests. For example, a source file

src/errors/normal_error/normal_error.rs

is matched with the test file under the tests folder:

test/errors/normal_error/normal_error_tests.rs

Shared utils used for testing are actually stored in the src tree under:

src/utils_tests/mod.rs # contains utils

The reason is, Bazel cannot access util files from within the test folder, but it can access the full src folder during testing. As a result, test utils have to be fully tested to count towards the code coverage score.

The usage of a prelude file is prohibited.

Code export

  • All public errors, traits, and errors are exported from src/lib.rs
  • internal modules remain private at the root level.

Code import

When importing from a crate, always import directly from the root level, for example:

use deep_causality_discovery::{ConsoleFormatter, ProcessAnalysis, ProcessResultFormatter};

Code conventions

Field visibility:

  • Public types: All fields will be private, and access will be provided through constructors, getters, and setters as appropriate.
  • Private types: Public fields may be used, provided they do not leak outside their defined scope.

Static Dispatch:

  • Use static dispatch
  • Avoid usage of dyn, trait objects, and dynamic dispatch

Coding style:

  • Prefer idiomatic zero cost abstractions
  • Prefer functional style i.e. map, flatmap, filter when dealing with collections

Safety and security style:

  • No unsafe. This is enforced repo-wide via [workspace.lints.rust] unsafe_code = "forbid" in the root Cargo.toml. All 48 workspace members opt in with [lints] and workspace = true in their own Cargo.toml — new crates MUST include this.
  • There are no exemptions.
  • Avoid macros in all lib code i.e. everything under /src. However, macros for testing are permissible when using sparingly i.e. for bulk testing many types implementing the same trait.
  • Avoid the introduction of external crates unless it is necessary for testing.