ruvector/deny.toml
rUv 22689a7511
Graph condensation: structure-preserving + differentiable min-cut (ruvector-graph-condense) (#547)
* Add ruvector-graph-condense: structure-preserving graph condensation

New crate implementing training-free, structure-preserving graph
condensation built on the dynamic min-cut engine (ruvector-mincut).
Collapses a feature graph into a small synthetic graph of super-nodes
(regions) while preserving cut structure and node provenance.

Positioning vs. SOTA (GCond/SFGC/GEOM/SGDD): those synthesise a fake
graph via bi-level gradient/distribution/trajectory matching and discard
the node->original mapping. This is the complementary, training-free
route the 2024-2026 surveys flag as under-explored: min-cut community
structure as the condensation prior, cuts preserved by construction
(boundary edges become weighted super-edges), and members retained per
super-node for audit/explainability. Closest published analogs are CGC
(clustering, 2025) and GCTD (tensor decomposition, 2025).

Components:
- NodeFeatures: validated per-vertex embeddings + optional labels
- CondensedNode/Edge/Graph: centroid, weight, class histogram, coherence,
  medoid representative, member provenance; round-trips to DynamicGraph
- GraphCondenser with 4 region methods:
  - WeakBoundary (default): single-pass union-find over weak-edge removal,
    linear-time, recovers planted structure
  - MinCutCommunity / Partition: delegate to the min-cut engine
    (CommunityDetector / GraphPartitioner); best-effort, documented as
    super-linear and prone to singleton-peeling on graphs without
    sharp bottlenecks
  - ConnectedComponents baseline
- metrics: retrain-free proxies (reduction ratios, intra-weight ratio,
  coherence, label purity) + opt-in cut_inflation via exact MinCutBuilder
- StreamingCondenser: lazy re-condensation for growing graphs
- PlantedPartition synthetic generator; criterion benchmarks

Benchmarks (this machine): WeakBoundary scales linearly (~4ms @ 2048
nodes); the recursive min-cut engine methods are super-linear (~24s @ 96
nodes), which is why WeakBoundary is the default.

33 unit tests + 1 doctest pass; clippy clean.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Add differentiable min-cut loss (diffcut) to graph condensation

Implements the open research gap flagged by the SOTA review: a
differentiable min-cut / normalized-cut objective used as the
condensation mechanism. The 2024-2026 surveys note that only spectral
terms (SGDD's Laplacian Energy Distribution, GDEM's eigenbasis) exist;
an explicit relaxed-min-cut loss in the condensation objective does not.

New `diffcut` module (after Bianchi et al., MinCutPool 2020):
- Relaxed normalized-cut loss L_cut = -Tr(SᵀAS)/Tr(SᵀDS) plus an
  orthogonality/anti-collapse term L_ortho, over a row-softmax soft
  assignment S (N×K) of learned logits.
- Analytic gradients (cut, ortho, and softmax backprop), all maths in
  f64, no autodiff dependency. Verified against central finite
  differences (gradient_matches_finite_differences passes to 1e-5).
- DiffCutCondenser: gradient-descent training -> DiffCutResult with
  soft_assignment() and hard_regions() (argmax grouping).
- Public min_cut_loss() for evaluating any soft assignment.

Wired in as CondenseMethod::DiffMinCut(DiffCutConfig): trains the soft
assignment, hardens to regions, then flows through the existing
provenance-preserving super-node/super-edge construction. The only
region method whose structure is *trained* to preserve the cut.

Tests: 36 unit (incl. gradient check + uniform-assignment behaviour) +
6 integration (recovery, determinism, errors) + doctest. clippy clean;
all source files <500 lines. Benchmarks add a diffcut training group.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* docs(adr): ADR-196 + ADR-197 for graph condensation

ADR-196: Structure-preserving graph condensation (ruvector-graph-condense)
 — context (SOTA gap + RuView/WorldGraph substrate), decision (training-
free coarsening-condensation with min-cut prior, provenance retained),
the CondenseMethod taxonomy with honest tradeoffs (WeakBoundary default;
engine methods peel + are super-linear), metrics, streaming, alternatives.

ADR-197: Differentiable min-cut condensation loss (diffcut) — the relaxed
normalized-cut + orthogonality objective (MinCutPool-style), analytic
gradients verified by finite differences, DiffCutCondenser + DiffMinCut
integration, and the novelty framing (differentiable min-cut term in the
condensation loss is unpublished as of 2026).

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Add WorldGraph example + momentum optimizer; harden diffcut for K>2

- examples/worldgraph.rs: RuView WorldGraph -> condense -> OccWorld demo.
  WeakBoundary condenses 600 observations into 12 event summaries (50x,
  100% activity purity, cut preserved 1.000); a smaller dense scene shows
  the trained DiffMinCut recovering ~86% activity purity.
- diffcut: add heavy-ball `momentum` to DiffCutConfig (default 0.0, all
  existing behaviour/tests/benchmarks unchanged) and unit-scale logit init
  for stronger symmetry-breaking at K>2.
- Extend the gradient check to K = 2, 3, 4 (proves the K-general gradient
  formulas; max abs error < 1e-5).
- Honest finding documented in ADR-197: DiffMinCut (MinCutPool-style) is
  K-sensitive — reliable at small/moderate K, underperforms WeakBoundary at
  large K, reinforcing WeakBoundary as the default (ADR-196).
- Workspace manifest validated (member resolves; crate is additive so it
  cannot break other crates).

43 tests pass (36 unit + 6 integration + 1 doctest); clippy clean; all
source files <500 lines.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Optimize trained min-cut for large K: Adam + warm-start + restarts

Plain/momentum GD from random init stalled the differentiable min-cut at
large K (12-event WorldGraph: ~30% purity, ~24s @ 96 nodes). Rebuilt the
optimizer so the trained method is viable at scale:

- Split loss math into cutloss.rs (CompactGraph + softmax + cut/ortho +
  analytic gradients, gradient-checked K=2,3,4); diffcut.rs now owns the
  optimizer/orchestration. Both files <500 lines.
- Optimizer enum: Adam (default; adaptive moments) and Sgd { momentum }.
- InitStrategy enum: WarmStart (default) seeds logits from the WeakBoundary
  structural prior and refines (coreset/K-Center idea), or Random.
- restarts: keep the lowest-loss run. Deterministic region ordering in
  warm-start so same seed => identical result.

Result on the 12-event WorldGraph example: DiffMinCut now reaches 100%
activity purity, cut preserved (inflation 1.000) — matching WeakBoundary —
in milliseconds (bench condense_diffcut: ~0.96ms @64, ~6.4ms @192 nodes;
was ~24s @96 under plain GD).

New tests: warm_start_recovers_many_clusters (K=8, purity>0.85),
warm_start_beats_random_at_large_k, warm_start_seeds_a_good_partition,
adam_refines_to_low_cut. Config call sites use ..Default::default().
ADR-197 updated. 47 tests pass (38 unit + 8 integration + 1 doctest);
clippy clean.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* diffcut scale levers: early-stop, Rayon parallelism, edge-minibatching

Three further optimizations for large/million-node graphs (off by default):

- Early-stopping (tolerance, default 1e-6): warm-start lands near the
  optimum, so stop when the loss plateaus. iterations_run() reports actual.
- Parallelism (parallel, Rayon): CSR row-parallel A·S plus parallel O(N·K²)
  SᵀS + ortho-gradient loops. Deterministic / bit-identical to sequential
  (same chunked partial-sum ordering), proven by a test.
- Edge-minibatching (minibatch_edges): stochastic gradient from a sampled
  edge subset, O(batch·K)/step; final loss still full-batch exact.

Refactor: cutloss.rs gains CSR adjacency + as_matrix (parallel) +
as_matrix_minibatch + a chunked gram(); loss_and_grad split so the optimizer
supplies A·S. New tests: parallel_matches_sequential_exactly,
minibatch_recovers_structure, early_stopping_cuts_iterations. New bench group
condense_diffcut_levers (1024 nodes, 4 cores: seq ~95ms, parallel ~83ms,
minibatch ~77ms). ADR-197 updated.

50 tests pass (38 unit + 11 integration + 1 doctest); clippy clean; all
source files <500 lines.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Add GNN accuracy-retention harness (closes the no-accuracy-validation gap)

Implements the graph-condensation field's core success metric: train a GNN
on the condensed graph, test on the ORIGINAL graph's held-out nodes, report
accuracy(condensed)/accuracy(full).

- gnn_eval.rs: self-contained, dependency-free 2-layer GCN (symmetric-
  normalised CSR propagation, ReLU, softmax-CE, Adam, analytic backprop).
  Gradient-checked against finite differences (<1e-6) and verified to learn a
  separable task.
- examples/accuracy_eval.rs + tests/accuracy.rs: the full protocol on a
  controlled synthetic node-classification task (planted communities as
  classes, noisy features so the graph carries real signal).

Measured: baseline (full-graph GNN) 100%. On an UNWEIGHTED graph (the SOTA
benchmark setting), DiffMinCut condensing 360 nodes -> 18 super-nodes (20x)
yields **100% retention** (GNN trained on 18 nodes matches the full-graph GNN
on held-out test nodes).

Also fixes a real failure the harness surfaced: on uniform-weight graphs
WeakBoundary collapses to one component; DiffMinCut's warm-start inherited
that collapse. Warm-start now falls back to random init when the structural
prior finds <2 regions, letting the min-cut objective do the partitioning
(retention 14.9% -> 66% at K=classes, 100% at K=3*classes).

Honest scope: controlled synthetic data, not Cora/Citeseer; WeakBoundary
still needs weight contrast (documented). 53 tests pass; clippy clean.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Add WASM bindings + gate Rayon behind a feature for wasm builds

- crates/ruvector-graph-condense-wasm: wasm-bindgen bindings exposing
  condense_weak / condense_diffmincut / version to JS. Graphs in as flat
  typed arrays, CondensedGraph out as JSON. Builds for
  wasm32-unknown-unknown (667 KB release, pre wasm-opt), so the condenser
  (including the trained DiffMinCut) runs in the browser / on the edge —
  the deployable-artifact goal from the original brief.
- ruvector-graph-condense: Rayon is now an optional `parallel` feature
  (default on for native, off for wasm — no threads on
  wasm32-unknown-unknown). cutloss.rs cfg-gates every Rayon path with a
  sequential fallback; no-default-features builds clean.
- getrandom `js` backend is wasm-target-gated so native feature
  unification is unaffected; ruvector-mincut built with its `wasm` feature.
- ADR-196 updated with the WASM deployment + accuracy-validation notes.

53 tests pass; clippy clean (both crates); native + wasm32 both build.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Add ruvector-perception: the layer under classification (delta->proof->action)

Beyond-SOTA wedge: instead of a better CSI classifier, build the substrate
underneath one. Pipeline: delta -> boundary -> coherence -> proof -> action.
Emits a structured DeltaWitness, not a class label, and requires evidence
(not confidence) before exercising bounded authority.

- modality.rs: physically-typed modalities (RF/vibration/acoustic/thermal/
  chemical/optical) with latency/decay/spoof-resistance — typed graph edges.
- state.rs: rolling per-(zone,modality) baselines + learned responsiveness.
- coherence.rs: zones as a coherence graph; dynamic min-cut isolates the moved
  boundary (reuses ruvector-mincut). Coherence = separation cleanliness.
- witness.rs: ProofGate (Ignore/Observe/Alert/Mutate) + SHA-256 evidence
  chain. Contradicted evidence is capped at Observe (no escalation on
  confidence alone). Contradiction = a modality that usually reacts here but
  stayed silent, weighted by spoof-resistance.
- engine.rs: orchestrates delta -> boundary -> contradiction -> novelty
  (nearest-prior) -> proof gate -> chained witness.
- absence.rs: missing expected continuation (bed_exit->bathroom->return) as a
  structural safety signal, not a threshold.

Flagship test reproduces the brief exactly: an inert object move yields
changed_boundary=table_left_zone, supporting={rf,vibration,acoustic},
contradicting={thermal}, novelty=high, action=observe. ADR-198 documents the
architecture and honest scope (mechanism on synthetic deltas, not validated on
real CSI).

11 tests pass; clippy clean; all files <500 lines.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Perception: 5 beyond-classification capability modules (swarm-built)

Built via a 5-agent parallel swarm, then integrated and validated. Each
emits structure, not a class label:

- captcha: Physical CAPTCHA — learned per-stimulus multi-modal challenge-
  response profiles; verifies a fresh response (delay/magnitude tolerance,
  spoof-resistance weighted) -> RealityProof. Detects replay/spoof.
- predict: Boundary-first world model — forecasts where coherence breaks next
  (instability = coherence*(1+contradiction), level + least-squares trend).
- identity: Resonant identity / continuity — per-object EWMA signature, cosine
  drift detection ("is this still the same physical thing?").
- hypothesis: Multi-modal disagreement engine — contradictions produce ranked
  hypotheses (RealEvent/SensorDrift/SensorRelocation/AdversarialReplay/
  EnvironmentalArtifact), not forced agreement.
- topology: Self-healing sensor topology — EWMA agreement graph; roles
  Critical/Redundant/Noisy/Normal. Critical = articulation point (removal
  fragments the graph) — replaced the agent's unreliable min-cut-partition
  rule with robust articulation detection so triangle/star outliers keep their
  real roles.

lib.rs re-exports all five. ADR-198 updated. 42 tests pass (38 unit + 2
integration + 2 doctest); clippy clean; all source files <500 lines.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* Perception: complete the substrate — custody, swarm, reality-graph, node

Final beyond-classification pieces (custody + swarm built by a 2-agent swarm;
reality + node integration built directly):

- custody: tamper-evident, replayable chain-of-custody ledger over witness
  evidence hashes (chain-linkage verification; honest scope: link integrity,
  not raw-signal re-hash).
- swarm: facility/swarm-scale fragility — coupling graph + global min-cut
  answers "where is the system closest to breaking?". Bottlenecks derived from
  the weakest link (edge weights), since the engine's min-cut value is reliable
  but its partition is not (same quirk handled in topology).
- reality: reality-graph agent grounding — an agent queries physical state
  (presence / changed-since / which-untrusted / action-allowed) and gets
  answers backed by witness evidence hashes, not prompt inference.
- node: NervousSystemNode appliance facade wiring engine + reality + custody +
  boundary forecaster; emits deltas/boundaries/witnesses/forecasts (no raw
  signal) and answers grounded queries.

Fixes during integration: swarm bottleneck now uses the weakest edge (engine
partition is unreliable); node test uses 3 zones (2-zone min-cut boundary is
ambiguous — a real limitation now documented). ADR-198 updated.

59 tests pass (54 unit + 2 integration + 3 doctest), deterministic; clippy
clean; all source files <500 lines.

https://claude.ai/code/session_01RehxmT96dnBFxStu9LJyKX

* chore(ci): wire condense+perception crates into publish + regression guard (#547)

Aligns the new ruvector-graph-condense, ruvector-graph-condense-wasm, and
ruvector-perception crates with the workspace release plumbing.

- Bump their ruvector-mincut (and graph-condense) dep pins from "2.0.1" to
  "2.2.3" to match the workspace version they are built and tested against.
  The old "^2.0.1" pin would resolve a crates.io publish against the stale
  published mincut 2.0.6, risking a crate that fails to compile downstream.
- publish-all.yml: publish the three crates (plus mincut as substrate) to
  crates.io in dependency order with index-settle waits, matching the
  existing --allow-dirty / continue-on-error style.
- regression-guard.yml: run the new crates' tests (they were build-checked
  but never tested in CI) and forbid regressing the mincut pin back to 2.0.x.

Co-Authored-By: claude-flow <ruv@ruv.net>

* fix(graph-condense): rustfmt, clippy -D warnings, and cargo-deny advisory (#547)

CI green-up for the new condense/perception crates:

- rustfmt: format all source/bench/example/test files in the new crates
  (the PR was committed unformatted; CI Rustfmt flagged all 29 files).
- clippy -D warnings: condense.rs used `sort_by(|a,b| key.cmp(&key))` which
  trips clippy::unnecessary_sort_by under `-D warnings`; switch to
  `sort_by_key`. (Earlier local clippy didn't deny warnings, so it slipped.)
- cargo-deny: ignore RUSTSEC-2026-0173 (proc-macro-error2 unmaintained).
  Pre-existing transitive dep (validator_derive -> validator, via the
  ruvector-scipix example), same crate family as the already-ignored
  RUSTSEC-2024-0370. Not introduced by this PR. Re-review 2026-07-01.

Co-Authored-By: claude-flow <ruv@ruv.net>

* docs(graph-condense): add crate READMEs for crates.io publish (#547)

The new graph-condense crates were wired to publish without a README (101/136
workspace crates have one; every published crate does). Add READMEs matching
the repo's badge-header convention and the `readme = "README.md"` field so the
crates.io pages render properly on first publish.

- ruvector-graph-condense: overview, SOTA positioning, quick-start (using the
  real NodeFeatures::new/set + DynamicGraph::insert_edge API), region-method
  table, and the honest ADR-196/197 limitations.
- ruvector-graph-condense-wasm: short binding README pointing at the core crate.

Perception crate intentionally left as-is (out of scope for this request).

Co-Authored-By: claude-flow <ruv@ruv.net>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruvnet <ruvnet@gmail.com>
2026-06-08 22:58:44 +02:00

221 lines
10 KiB
TOML

# cargo-deny configuration — supply-chain policy for the ruvector
# workspace. See the supply-chain CI workflow (`.github/workflows/
# supply-chain.yml`) for how this gets enforced on every PR + on a
# weekly scheduled scan.
#
# Run locally:
# cargo install --locked cargo-deny
# cargo deny check
#
# Four sub-checks run: advisories, bans, licenses, sources.
# Each fails the run independently; together they form the crate-graph
# half of our supply-chain defence (npm side is in the same workflow).
[graph]
# Sensible target set so we don't pull in checks for triples we never
# build day-to-day. wasm32-unknown-unknown is gated per-crate by the
# `wasm` features and gets its own checks in the wasm CI jobs.
targets = [
{ triple = "x86_64-unknown-linux-gnu" },
{ triple = "aarch64-unknown-linux-gnu" },
{ triple = "x86_64-apple-darwin" },
{ triple = "aarch64-apple-darwin" },
]
# ─────────────────────────────────────────────────────────────────────
# 1) advisories — RustSec DB scan
# ─────────────────────────────────────────────────────────────────────
[advisories]
db-urls = ["https://github.com/RustSec/advisory-db"]
version = 2
# Surface yanked crates as warnings. Promote to `deny` once we've
# migrated off whichever transitive holds the yanked version.
yanked = "warn"
# Whitelist specific RUSTSEC IDs with justification + re-review date.
# Every entry MUST carry a justification and an explicit re-review
# date — we revisit on each minor release at minimum. Dependabot will
# auto-resolve most of these as upstreams publish fixes; this list is
# meant to shrink over time.
ignore = [
# ── Real vulnerabilities (need active migration path) ────────────
# rsa 0.9.x — Marvin Attack timing sidechannel (RUSTSEC-2023-0071).
# No patched version exists; the RustCrypto/RSA team is rewriting
# to constant-time. Used by `ruvector-kalshi` for Kalshi exchange
# API signing (RSA-PSS-SHA256, mandated by the exchange). Mitigation
# per the advisory: "local use on a non-compromised computer is
# fine" — we sign locally and an attacker would need to observe
# sub-ms timing across many requests through the network response
# timing to recover the key. Risk is acceptable for trading-bot
# use; re-review on 2026-08-01 or when `rsa 0.10` ships with the
# constant-time fix (track: https://github.com/RustCrypto/RSA/issues/626).
"RUSTSEC-2023-0071",
# ── Unsoundness (no exploit path in our usage) ───────────────────
# rand 0.8.5 — unsound only when paired with a *custom logger* that
# logs during random number generation (RUSTSEC-2026-0097). We use
# `tracing` and never log inside RNG draws; the unsound condition
# cannot be triggered. Re-review on `rand 0.9` adoption across the
# workspace.
"RUSTSEC-2026-0097",
# imageproc 0.25.0 — three unsoundness advisories around image
# sampling / bounds checks. Pulled transitively via the scipix
# examples crate, never reached by the publish artifacts of any
# crates.io-published member. Unsound != exploitable here: inputs
# are caller-controlled image buffers in offline experiments.
# Re-review on 2026-08-01 or when imageproc publishes 0.26 with
# the fixes.
"RUSTSEC-2026-0115",
"RUSTSEC-2026-0116",
"RUSTSEC-2026-0117",
# ── Unmaintained transitive deps (informational, no CVE) ─────────
# proc-macro-error 1.x — unmaintained, transitively required by
# several proc-macro deps (clap-derive ecosystem). 2.x is API
# incompatible. Dependabot tracking. Re-review on 2026-07-01.
"RUSTSEC-2024-0370",
# proc-macro-error2 — the (also now unmaintained) fork of the above,
# pulled transitively via validator_derive -> validator (ruvector-scipix
# example). Same crate family as RUSTSEC-2024-0370, no maintained
# successor yet. Informational. Re-review on 2026-07-01.
"RUSTSEC-2026-0173",
# number_prefix — unmaintained, used transitively by indicatif. No
# known successor; indicatif itself is still maintained. Informational.
"RUSTSEC-2025-0119",
# paste 1.0.x — archived upstream 2024-10. Pulled transitively via
# nalgebra/simba and several proc-macro deps. No vulnerability,
# just informational. Re-review on 2026-08-01.
"RUSTSEC-2024-0436",
# bincode 1.x — unmaintained, 2.x is API-incompatible. Multiple
# call sites across rvf + serialization layers; migration queued.
# Re-review on 2026-07-01.
"RUSTSEC-2025-0141",
# instant 0.1.x — unmaintained. Transitive via async-std / wasm
# adapters. Replacement is `web-time` but several transitives still
# pin instant directly. Re-review on 2026-07-15.
"RUSTSEC-2024-0384",
# rand_os 0.x — unmaintained, replaced by getrandom. Transitive via
# legacy rand internals; modern paths use getrandom directly.
"RUSTSEC-2021-0140",
# core2 0.4.0 — yanked, but pulled transitively via the rav1e/
# image/imageproc chain (offline-only scipix examples crate).
# Re-review when imageproc bumps off ravif 0.13.
"RUSTSEC-2025-0124",
# rustls-pemfile 1.x — unmaintained, replaced by rustls-pki-types'
# builtin PEM parser. Transitive via reqwest / tokio-tungstenite.
# Migration is a transitive bump; Dependabot tracking.
"RUSTSEC-2025-0134",
# rusttype 0.9 — unmaintained (RUSTSEC-2026-0105). Used by
# imageproc's text-rendering path which we don't exercise (scipix
# offline experiments only). No safe upgrade available. Re-review
# 2026-08-01.
"RUSTSEC-2026-0105",
]
# ─────────────────────────────────────────────────────────────────────
# 2) bans — explicit crate-name allow/block list
# ─────────────────────────────────────────────────────────────────────
[bans]
# 136-member workspace pulls both Tokio and async-std families,
# producing legitimate version skew (e.g. nalgebra 0.32 vs 0.33 across
# linear-algebra crates). Track for cleanup but `warn`, not `deny`.
multiple-versions = "warn"
# Refuse `version = "*"` for crates.io deps in any of our Cargo.tomls
# — that's how typosquatting + accidental floats land malicious
# versions. Demoted to `warn` for now because several internal/path
# wildcards exist in the mcp-brain + consciousness experiment crates
# (those use `workspace = "*"` for path-only deps which cargo-deny
# can't always distinguish from registry wildcards). Tracked for
# tightening to `deny` once those are migrated to explicit version
# constraints. Re-review on 2026-08-01.
wildcards = "warn"
# Highlight transitively-pulled-in deep deps so reviewers can audit
# tree growth without explicit blessing.
highlight = "all"
# Concretely forbidden crates — empty for now. Use this slot to
# quickly block a compromised package mid-flight without editing the
# workflow.
deny = []
# Allow internal workspace path deps to use `version = "*"` until the
# tighten-up pass lands. Listed crates have been audited as path-only.
allow-wildcard-paths = true
# ─────────────────────────────────────────────────────────────────────
# 3) licenses — what we'll allow in the graph
# ─────────────────────────────────────────────────────────────────────
[licenses]
version = 2
# Matches `actions/dependency-review-action`'s allow-list in the
# supply-chain workflow so the two checks agree.
#
# Additions vs sublinear-time-solver's allowlist:
# * BSL-1.0 — Boost Software License (xxhash-rust transitive
# via rvf-wire → mcp-brain-server + benchmarks)
# * CDLA-Permissive-2.0 — used by tch-rs / onnxruntime style deps
# * NCSA — University of Illinois/NCSA Open Source
# License (LLVM family deps)
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Unicode-DFS-2016",
"Unicode-3.0",
"MPL-2.0",
"Zlib",
"CC0-1.0",
"BSL-1.0",
"CDLA-Permissive-2.0",
"NCSA",
]
confidence-threshold = 0.8
exceptions = []
# Workspace-internal crates without `license = "..."` set are research
# / examples crates with `publish = false`. Ignore them rather than
# failing the run — they're never shipped to crates.io. If one is ever
# flipped to `publish = true`, the publish flow's `cargo publish` step
# will refuse it without an explicit license, so this is safe.
private = { ignore = true }
# ─────────────────────────────────────────────────────────────────────
# 4) sources — which registries / git remotes the graph can pull from
# ─────────────────────────────────────────────────────────────────────
[sources]
# Default: only the official crates.io registry. Anything else (private
# mirror, git dep) must be explicitly allowed.
unknown-registry = "deny"
# `warn` instead of `deny` for ruvector because the workspace pulls
# several legitimate git deps (vendored hailo bindings, in-flight
# upstream fixes pinned to commits). Promote to `deny` once those
# have crates.io releases. Each unknown-git appearance shows up in
# the CI log so reviewers can challenge it on a per-PR basis.
unknown-git = "warn"
# Allow-list for git remotes — populated on demand. If a future PR
# needs a git dep, this is where the reviewer adds it with a
# justification comment.
allow-git = []
allow-registry = ["https://github.com/rust-lang/crates.io-index"]