Detectors
Reforge emits refactoring signals from threshold checks, Tree-sitter analysis, git churn, and heuristic drift detectors. Findings are signals for review; they are not automatic proof that code must be changed, that code is low quality, or that a bug exists.
Every finding kind is also described by the report-level detector_manifest.
The manifest declares its primary maintainability construct, signal mechanism,
refactoring action, entity scope, detection approach, supported languages,
precision risk, composite parent, and typed detector relations. Clustering
consumes the relation contract so shared paths alone cannot double-count or
merge unrelated detectors. See Metric Ontology.
File and Directory Signals
large_file: source file line count exceeds--max-file-lines.large_directory: direct source-file count exceeds--max-dir-files.debt_marker: a comment line containsTODOorFIXME.
Hidden paths are skipped unless --include-hidden is set. Generated and
dependency directories are skipped unless --include-generated is set. Test
files and directories are scanned by default; --exclude-tests removes them
before detector-specific analysis runs.
Similar Functions
similar_functions uses Tree-sitter to extract named functions and methods in
Rust, JavaScript, TypeScript/TSX, Python, Go, Java, C#, Kotlin, PHP, and Ruby.
Function bodies are normalized so identifiers become ID, strings become
STR, and numbers become NUM.
Candidates are grouped only within the same language family and same category of function or method. Similarity uses length ratio, multiset overlap, and a longest-common-subsequence check.
Controls:
--min-similar-functions--min-function-tokens--function-similarity--include-test-similarity
Test files are excluded from this detector by default.
Structural Signals
Structural detectors use Tree-sitter for supported languages.
long_function: function line span exceeds--max-function-lines.complex_function: estimated complexity exceeds--max-function-complexity.deep_nesting: nested control-flow depth exceeds--max-nesting-depth.many_parameters: parameter count exceeds--max-function-parameters.readability_risk: one function combines at least two function-level readability signals, such as length, complexity, nesting, or parameter pressure.large_type: type line span or member count exceeds--max-type-linesor--max-type-members.large_public_surface: public/exported item count exceeds--max-public-items.import_heavy_file: import count exceeds--max-imports.function_proliferation: a production file has many functions, high functions-per-100-lines density, and a high percentage of small simple functions. This is an over-splitting signal, not proof that any function is unused.
Tests are excluded from general structural findings unless
--include-test-structure is passed.
For Rust, large_public_surface counts items with visibility modifiers such as
pub, pub(crate), and pub(super), including public re-exports, because each
one expands the module surface visible to another scope.
Unused Functions
unused_function builds a conservative project-wide identifier index for
Rust, JavaScript, TypeScript/TSX, Python, and Go. It reports private named free
functions that have no same-name references outside their own function body.
Java, C#, Kotlin, PHP, and Ruby are parsed for structural and similarity
signals, but skipped for unused-function candidates until their reference and
visibility rules can be modeled more precisely.
The detector skips public or exported functions, methods, common entry-point
names such as main and init, and test helper definitions by default.
References from scanned test files still count, so production helpers called
only by tests are not reported unless tests are excluded from the scan.
Dependency Graph Signals
dependency_cycle and dependency_hub use a conservative source-file import
graph. The detector resolves only imports that point to another scanned source
file under the scan root, such as relative JavaScript/TypeScript imports,
Rust mod declarations, Python relative imports, Ruby require_relative
calls, and quoted C/C++ includes that resolve to scanned source files.
dependency_cycle: a resolved strongly connected component spans multiple source files. The finding reports cycle size, internal dependency edge count, and internal edge density.dependency_hub: a project with enough resolved graph data has a file with unusually high fan-in or fan-out. The finding reports direct fan-in/fan-out, transitive reach, dependency depth, and instability percentage so broad, deep, and mixed-responsibility hubs rank higher. Dependency depth is the longest path through the strongly connected component condensation graph. Files in the same cycle therefore share one component depth; cycle size and density remain evidence ofdependency_cycleinstead of being counted again as depth.
External packages, unresolved aliases, generated paths skipped by scan filters, and ambiguous language-specific module systems are ignored rather than guessed.
Duplication and Test-Risk Signals
repeated_literal: string or numeric literals occur at least--min-repeated-literal-occurrencestimes after normalization and filtering.repeated_error_pattern: repeated catch/except/error handling patterns are found across supported languages.data_clump: repeated parameter groups occur at least--min-data-clump-occurrencestimes.test_duplication: repeated setup, fixture, mock, fake, or before-hook patterns occur in tests.happy_path_only_tests: a test file has at least three test cases with assertion evidence but no negative, error, or boundary evidence.
Repeated-literal confidence is lower when the literal appears only in tests or looks like report/fixture text.
Drift Signals
file_naming_drift: a directory mixes naming styles such assnake_case,kebab-case,PascalCase,camelCase,lowercase,dot.separated, ormixed.directory_drift: a directory mixes more concepts than the directory-size threshold allows.parallel_implementation: multiple functions/classes appear to implement the same capability.shadowed_abstraction: helper/common/shared/util abstractions are shadowed by similar local helpers.duplicate_type_shape: multiple type-like shapes share enough fields to suggest duplicated data modeling.config_key_drift: config, route, env, endpoint, token, or similar keys are repeated across locations.fixture_factory_drift: test factory, fixture, mock, fake, or sample concepts are repeated across locations.generic_bucket_drift: generic directories such ascommon,helpers,shared, orutilsaccumulate unrelated concepts.adapter_boundary_bypass: a boundary module exists, but other files make direct HTTP, config, filesystem, or logging calls.stale_compatibility_path: legacy, deprecated, fallback, shim, polyfill, or versioned compatibility paths appear without a clear sunset, owner, or migration boundary.
Drift detectors use path and identifier heuristics, so grouped cross-file findings deserve more weight than isolated info-level findings.
Documentation Signals
When the scan root looks like a project, Reforge checks for a stable documentation set.
missing_documentation_set: expected docs are missing underdocs/or at the repository root.missing_user_guide: user-guide topics such as installation, quick start, CLI, configuration, output, and troubleshooting are missing.missing_report_schema_docs: JSON/YAML fields and compatibility expectations are undocumented.missing_metrics_model_docs: raw metrics, findings, hotspots, priority, or confidence are undocumented.missing_architecture_docs: scan pipeline, detector boundaries, data flow, or extension points are undocumented.stale_cli_documentation: docs mention CLI flags but omit current flags.stale_schema_documentation: report-schema docs omit current fields.
Expected docs include a docs index, user guide, configuration reference, report schema, metrics model, detector reference, architecture guide, and contributing guide.
Interpreting Detector Output
Prefer findings with high priority, high confidence, cross-file spread, and clear related locations. Treat low-confidence heuristic findings as prompts for inspection, not automatic refactor instructions.
findings=0 means no findings remain after scoring, filters, and
suppressions. It does not prove that the scanned code is healthy, bug-free, or
free of maintainability pressure. Check hotspot watchlists, raw metrics, and
suppression summary context when explaining an empty finding list.
Filtering and Suppression
Finding-kind controls use the snake-case detector names above. --only keeps
only selected kinds, --exclude-detector removes selected kinds,
--min-priority keeps findings at or above the final scored priority, and
--severity warning keeps warning and critical findings.
Intentional findings can be suppressed in source comments with
reforge:ignore, reforge:ignore-next-line, or reforge:ignore-file.
Each directive accepts an optional comma-separated kind list followed by a
reason. Long-lived suppressions can also be recorded in reforge.toml with
[[suppressions]] entries.
Suppressions remove matching findings from reports and CI gate selection, but they do not remove raw metrics or hotspot watchlist entries. Suppression summary information exists to preserve that audit context and prevent zero unsuppressed findings from being read as zero observed signals.