Skip to main content

ovecc components

Recovers subsystems from the dependency graph with ACDC's two-phase clustering (Tzerpos & Holt, WCRE 2000), as a second view beside the directory-derived modules — not a replacement for them.

Usage: ovecc components [OPTIONS]

Module names come from the folder tree, so your layout decides the structure ovecc reports. This command asks the graph instead: if nobody had chosen the directories, what subsystems would the imports themselves describe? Where the two views disagree is the reportable fact.

How it clusters

Phase one applies subsystem patterns:

PatternClaims
body-headerFolds x.c / x.h into one unit
support-libraryFiles whose in-degree exceeds --support-in-degree — used by everything, dominated by nothing
subgraph-dominatorFor each file, everything reachable only through it

Phase two adopts the leftovers into whichever subsystem they are most connected to.

The output is a containment tree, not a flat partition, and split_modules names every module the two views disagree about.

Example

$ ovecc components
Components: 34 subsystem(s) recovered, 14 module(s) named by directory
91 file(s) claimed by a pattern, 38 adopted

Modules the layout collapses (7):
ovecc-db -> 2 subsystems: crates/ovecc-db, crates/ovecc-db/src/lib.rs
ovecc-graph -> 3 subsystems: crates/ovecc-cli/src/commands/mod.rs, crates/ovecc-graph/src/lib.rs, crates/ovecc-indexer/src/lib.rs

<support> [support library] 4 file(s), 1 adopted, modules: ovecc-cli, ovecc-core

crates/ovecc-indexer/src/lib.rs [subgraph dominator] 17 file(s), 6 adopted, modules: ovecc-cli, ovecc-core, ovecc-dataflow, ovecc-graph, ovecc-indexer, ovecc-parser, ovecc-rules
contains: crates/ovecc-graph/src/lib.rs, crates/ovecc-parser/src/lib.rs

crates/ovecc-graph/src/lib.rs [subgraph dominator] 2 file(s), modules: ovecc-graph
inside: crates/ovecc-indexer/src/lib.rs

contains and inside are the containment tree the flat module list cannot express.

Determinism

The published algorithm leaves tie-breaking unspecified — which is why the ICSE 2015 comparison had to run it five times per subject and report the best score. Here ties break on connectivity, then cardinality, then name, so one index always yields one clustering, byte for byte.

What it will not tell you

Dominance groups everything behind one entry point

A feature with a single barrel index.ts is one subsystem, however many slices it contains — even when those slices import each other in a cycle. Nothing outside the feature imports the slices directly, so the barrel dominates them all.

That is a property of dominance, not a bug, and it is pinned by tests rather than left for you to discover. For the slice-level question use diagnose (directory granularity) or raise [architecture] module_depth. The two commands answer different questions.

Accuracy against a published ground truth has not been measured for this implementation, so the command makes no accuracy claim. Treat it as a second opinion that is cheap to consult, not an authority that overrides your layout.

Options

OptionEffect
--target <substr>Scope to subsystems whose name, files, or modules mention this
--max-size <n>Largest file count a dominator subsystem may claim (default 20)
--support-in-degree <n>In-degree above which a file counts as a support library (default 20)

Plus the global options.

Counts stay whole-repository under --target, so a scoped view still says what it is a slice of.