Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Overview

Structural analysis for real codebases

See what deserves a refactor.
See the evidence first.

Reforge analyzes the structure of a codebase, explains every finding, and makes gaps in analysis visible.

reforge analyze . --output html --output-file reforge-report.html

From signal to decision

Reforge does not hide structural observations behind a score. It gives reviewers the context needed to decide whether a change is worthwhile.

01

Find the pressure points

Surface duplication, oversized responsibilities, dependency tangles, naming drift, and difficult value paths.

02

Inspect the evidence

Trace each finding back to its rule, measurements, source locations, and exact value-flow witness when available.

03

Know the limits

See partial and unsupported analysis explicitly. No findings never means more coverage than Reforge actually observed.

What Codebase looks for

Structure

Responsibilities

Find oversized files, functions, types, public surfaces, and directories that may own too much.

Patterns

Duplication and drift

Inspect repeated implementations, overlapping shapes, generic buckets, naming drift, and dependency tangles.

See how Codebase analysis works →

Designed for review, not scoring

Findings are inspection prompts—not severity labels, priorities, or defect predictions. Reforge runs locally, uploads no source code, and collects no telemetry. Use it interactively, generate a standalone HTML report, or compare reviewed JSON baselines in CI. An advanced Dataflow analysis is available when exact value-path inspection is needed, but it is not required for normal Codebase use.

User guide

Install

The verified release installer chooses the supported asset for the current OS and CPU, validates it against the release SHA256SUMS, checks reforge --version, and atomically installs the binary. It also installs the reforge-analyze Codex skill unless disabled.

Unix:

curl -fsSL https://raw.githubusercontent.com/LyleMi/Reforge/main/scripts/install.sh | sh
# Pin a release or choose a destination:
curl -fsSL https://raw.githubusercontent.com/LyleMi/Reforge/main/scripts/install.sh | \
  sh -s -- --version v0.2.0 --bin-dir "$HOME/.local/bin"

The Unix default is ${REFORGE_INSTALL_DIR:-$HOME/.local/bin}. Supported assets are Linux x86_64 and macOS x86_64/aarch64.

PowerShell:

$installer = Join-Path $env:TEMP "install-reforge.ps1"
irm https://raw.githubusercontent.com/LyleMi/Reforge/main/scripts/install.ps1 -OutFile $installer
& $installer
# Pin a release or choose a destination:
& $installer -Version v0.2.0 -BinDir C:\Tools\Reforge

Windows x86_64 defaults to %LOCALAPPDATA%\Reforge\bin. Use --skip-skill or -SkipSkill to install only the binary. Neither installer edits PATH; when necessary it prints the exact command to add the selected directory. Re-running an installer safely replaces the same version or upgrades it.

From a source checkout, the existing scripts/install-reforge.sh, scripts/install-reforge.ps1, and .bat wrapper remain available for cargo install --path development workflows.

Analyze

Run the default Codebase analysis:

reforge analyze . --reproducible

Dataflow is explicit. Run it alone or combine both core analyses over one workspace index:

reforge analyze . --analysis dataflow --output json --reproducible
reforge analyze . --analysis codebase --analysis dataflow --reproducible

Use --output and --output-file for human, HTML, JSON, YAML, or SARIF reports. Raw Codebase metrics and the complete Flow IR are opt-in debug sidecars:

reforge analyze . --analysis codebase --metrics-output metrics.json
reforge analyze . --analysis dataflow --flow-ir-output flow-ir.json

Read a report

Treat issues as the only decision units. Each Issue owns one typed subject and one or more Evidence records. Evidence identifies the rule and may include measurements, locations, and an ordered Dataflow witness.

Read Coverage before interpreting absence. Check the selected analysis status, every language receipt, capability limitation, rule execution, and suppression count. An empty Issue list is an observed zero only where Coverage is observable. Dataflow never represents a partial or unresolved path as exact.

Reforge intentionally emits no health score, severity, priority, or defect probability.

Baselines and CI gates

A baseline must use a compatible report format with the same producer, identity scheme, and workspace identity. Producer versions and unrelated analysis sets may differ. Coverage, scope, configuration, policy, or rule-semantic changes produce an unknown baseline state instead of claiming that an Issue is new or resolved.

After reviewing and storing a baseline report, gate new, updated, or unknown policy Issues with:

reforge analyze . --output json --output-file current.json \
  --baseline reforge-baseline.json --gate new --reproducible

--gate all fails on every current policy Issue. Rules are preview/off by default; enable and enforce the selected rule IDs in versioned reforge.toml.

Configuration and rules

reforge init writes a versioned configuration. Use reforge config validate, reforge config show, and reforge rules --output json to inspect effective settings and rule contracts. Durable settings belong in reforge.toml; temporary overrides use --set key=value.

Troubleshooting

Use Coverage and its capability limitations when zero Issues are reported. Regenerate incompatible older reports rather than editing them. If a Dataflow policy is rejected, verify that it names one supported language and that every source and sink path/symbol names exactly one frontend declaration.

Configuration

reforge.toml is versioned with version = 2. Generate it with reforge init.

version = 2

[analysis]
enabled = ["codebase"]

[scope]
include-hidden = false
include-generated = false
no-gitignore = false
exclude-tests = false
ignore-paths = []

[rules]
enable = []
disable = []
enforce = []

[codebase]
preset = "balanced"
churn = "auto"
max-file-lines = 600

[dataflow.search]
max-path-steps = 24
max-function-hops = 8
max-module-hops = 8
max-paths-per-source = 100
max-sinks-per-source = 100
work-budget = 100000

[dataflow.relay]
min-function-hops = 4
min-module-hops = 2
min-relay-percent = 90

[dataflow.fan-out]
min-sinks = 4
min-modules = 3

Rule arrays require complete IDs. Duplicate, conflicting, and unknown IDs are errors. enforce implies enable and accepts only stable rules. Experimental rules remain internal observations; preview rules are off unless enabled and can only produce advisory Issues. Only explicitly enforced stable rules produce policy Issues or participate in a gate.

Each Dataflow policy is single-language and names exact sink declarations:

[[dataflow.policies]]
name = "http-client"
language = "typescript"
protected-paths = ["src/domain/**"]
adapter-paths = ["src/adapters/http/**"]
exempt-paths = ["src/bin/**"]

[[dataflow.policies.sinks]]
path = "src/transport.ts"
symbol = "send"

A policy is rejected when its language is unsupported or a sink does not match exactly one public source symbol. Adapter bypass evidence requires a complete policy and an all-exact, value-preserving witness. Search budgets limit exploration and are not smell thresholds.

The versioned file is parsed as optional typed fields. Reforge then creates one complete effective configuration by applying built-in defaults, preset, configuration file, --set, and CLI scope overrides in that order. reforge config show prints every effective leaf together with its source.

Codebase analysis

Codebase is Reforge’s default analysis. It reviews repository structure and produces evidence-backed findings for maintainers to inspect before deciding on a refactor.

reforge analyze .

What it examines

Codebase builds one project-wide index before applying any rule. That index contains files, directories, declared functions and types, imports, local dependencies, naming patterns, repeated syntax, test structure, and optional Git history.

Rules use that shared view to look for four broad kinds of pressure:

AreaTypical findingsReview question
ResponsibilitiesLarge files and types, long or complex functions, broad directoriesDoes this unit own more than one reason to change?
DuplicationSimilar functions, repeated literals, repeated setup, overlapping type shapesIs the repetition intentional, or is a shared concept missing?
ArchitectureDependency cycles and hubs, parallel implementations, boundary bypassesIs ownership clear, and do dependencies point in the intended direction?
ConsistencyNaming drift, generic buckets, stale compatibility paths, debt markersHas a temporary or local convention spread beyond its original purpose?

The complete list is in the Rule Reference.

Enable the rules you want to review

Rules start as opt-in previews. Running Codebase still records its coverage, but a rule produces findings only after it is enabled in reforge.toml:

version = 2

[analysis]
enabled = ["codebase"]

[rules]
enable = [
  "reforge.codebase.large_file",
  "reforge.codebase.long_function",
  "reforge.codebase.dependency_cycle",
  "reforge.codebase.similar_functions",
]

[codebase]
max-file-lines = 600
max-function-lines = 80

Start with a small set whose meaning is easy to review in your repository. Adjust a threshold when the evidence is consistently too broad or too narrow; do not tune it merely to force a clean report.

Read a finding

A finding is the unit to review. It names one file, symbol, repository, or related group and contains one or more Evidence records. Evidence answers three questions:

  1. Which rule made the observation?
  2. Where in the source was it observed?
  3. Which measurement crossed the configured threshold?

Legitimate exceptions are expected. Generated facades, protocol signatures, composition roots, test builders, and deliberate compatibility layers can all look unusual for good reasons. Keep those decisions visible with a documented suppression instead of weakening a useful rule globally.

Check Coverage before trusting an empty result

Coverage records the files and languages seen by Codebase, the rules that ran, and any limitations. An empty findings list means only that the enabled rules found nothing within the observed surface. It does not prove that the codebase is healthy or defect-free.

Generate a report

Use the terminal output for quick review or create a standalone HTML file for a larger repository:

reforge analyze .
reforge analyze . --output html --output-file reforge-report.html
reforge analyze . --output json --output-file reforge-report.json --reproducible

JSON is the appropriate format for reviewed baselines and CI. See the User Guide for the baseline workflow and Configuration for scope, thresholds, and suppressions.

Advanced value-path analysis

Codebase is sufficient for normal structural review. Reforge also offers an opt-in Dataflow analysis for teams that need conservative, source-to-sink value paths or explicit adapter-boundary policies.

Rule cards

Every core rule is a refactoring-inspection claim, not a defect prediction, health score, generic priority, or automatic architecture inference. All cards inherit these non-goals. A finding’s identity comes from its typed subject and the rule-specific semantic anchor, not prose, ordering, checkout location, or line numbers. Measurement, threshold, evidence-set, or witness changes update the finding’s content fingerprint.

All rules below are currently preview, default_enabled = false, validation_basis = fixture, semantic version 1.0.0, and ineligible for enforcement. A language can become stable only through the audited calibration protocol in calibration/README.md; other languages remain preview.

RuleClaim / inspection questionCapabilityPositive and negative fixturesLegitimate exceptions
reforge.codebase.large_fileA file exceeds the configured line boundary; is responsibility ownership too broad?file inventoryover/under thresholdgenerated facades, declarative tables
reforge.codebase.large_directoryA directory owns more direct source files than configured.directory inventorywide/narrow directoriesflat packages with explicit ownership
reforge.codebase.debt_markerA source comment explicitly declares TODO/FIXME debt.source textcomment/non-comment markersgenerated or externally tracked markers
reforge.codebase.similar_functionsMultiple normalized bodies are structurally similar enough to inspect together.parsed syntax similaritycloned/distinct bodiesprotocol implementations, tests
reforge.codebase.long_functionA declared function exceeds the configured line span.syntax and symbolslong/short functionsgenerated parsers, linear tables
reforge.codebase.complex_functionEstimated branch complexity exceeds the configured bound.parsed control syntaxbranch-heavy/linear functionsexplicit state machines
reforge.codebase.deep_nestingLexical control nesting exceeds the configured bound.parsed control syntaxnested/guard-clause fixturesrecursive walkers
reforge.codebase.many_parametersA function declares more parameters than configured.symbol parametersover/under arityserialization and FFI boundaries
reforge.codebase.large_typeA type exceeds configured span or member count.type observationslarge/small declarationsgenerated schemas
reforge.codebase.large_public_surfaceA file exports more items than configured.export syntaxbroad/narrow modulesdeliberate prelude or facade
reforge.codebase.import_heavy_fileA file imports more dependencies than configured.import syntaxover/under import countcomposition roots
reforge.codebase.function_proliferationA file combines high function count, density, and small-function ratio.function inventorydense/sparse filesparser combinators
reforge.codebase.unused_functionA private symbol has no supported project-local reference.symbols and referencesreferenced/unreferenced symbolsreflection, callbacks, macros
reforge.codebase.repeated_literalA literal repeats enough to inspect ownership.parsed literalsrepeated/unique literalsprotocol constants and test data
reforge.codebase.repeated_error_patternError-handling syntax repeats across sites.parsed error syntaxrepeated/distinct handlersintentionally local recovery
reforge.codebase.test_duplicationTest setup patterns repeat across tests.parsed test syntaxduplicated/distinct setupreadability-focused local setup
reforge.codebase.happy_path_only_testsA test group has assertions without detected failure/boundary cases.test syntaxpositive-only/mixed testsbehavior proven elsewhere
reforge.codebase.file_naming_driftA directory mixes file naming conventions.path inventorymixed/uniform nameslanguage-required names
reforge.codebase.directory_driftDirectory concepts exceed the configured ownership bound.paths and syntax namesmixed/cohesive fixturesplugin registries
reforge.codebase.data_clumpThe same parameter combination recurs across functions.symbol parametersrecurring/distinct setsstable protocol signatures
reforge.codebase.parallel_implementationSimilarly named capabilities are implemented independently.symbol conceptsparallel/unrelated namesplatform-specific variants
reforge.codebase.shadowed_abstractionLocal helpers overlap a shared abstraction.symbols and conceptslocal/shared overlapdeliberate compatibility shims
reforge.codebase.duplicate_type_shapeType field shapes substantially overlap.type fieldsoverlapping/distinct shapesboundary DTOs
reforge.codebase.config_key_driftConfiguration-like keys repeat or drift.literal conceptsrepeated/distinct keysexternal protocol keys
reforge.codebase.fixture_factory_driftTest fixture/factory concepts repeat independently.test symbolsduplicated/distinct factoriesdomain-specific builders
reforge.codebase.generic_bucket_driftA generic directory or file accumulates unrelated concepts.typed file/directory subjectsgeneric/cohesive bucketsintentionally tiny shared kernels
reforge.codebase.adapter_boundary_bypassNaming/syntax suggests direct access around an adapter.heuristic conceptsbypass/non-bypass fixturesmigration and bootstrap code
reforge.codebase.stale_compatibility_pathCompatibility markers lack an explicit retirement boundary.parsed compatibility syntaxstale/owned pathssupported long-term compatibility
reforge.codebase.dependency_cycleResolved project-local dependencies form a cycle.dependency graphcyclic/acyclic graphsmutually recursive generated modules
reforge.codebase.dependency_hubA file has unusually broad/deep resolved dependency topology.dependency graphhub/leaf graphscomposition roots and public facades
reforge.dataflow.adapter_flow_bypassAn exact, value-preserving path violates a complete single-language adapter policy.exact local/interprocedural flowexact bypass/conforming and unsupported fixturesexplicit exemptions
reforge.dataflow.excessive_relayAn exact path contains configured forwarding depth; inspect ownership only.exact direct-call flowlong/short relay pathspipelines, middleware, telemetry
reforge.dataflow.flow_fan_outOne exact source reaches many supported sinks/modules.exact direct-call flowfan-out/narrow pathsorchestrators and event distribution

Similarity, literal, generic-bucket, unused-function, adapter, relay, and fan-out heuristics remain preview/off until each language independently meets the calibration gates. Self-scan is regression data only and cannot promote a rule or select a threshold.

Dataflow

Dataflow builds a language-neutral Flow IR for Rust, JavaScript/TypeScript/TSX, and Python. Selecting Dataflow records internal observations and capability receipts; enabled preview rules can surface advisories, while configured policies add exact bypass evaluation.

Coverage retains every language discovered in the shared workspace index. Rust, JavaScript, TypeScript, TSX, and Python receive rule observations; other languages are explicitly unsupported. Parse failures, unresolved edges, path truncation, and missing policy configuration use stable language/rule limitation codes and explicit capability receipts.

Preview rules

  • reforge.dataflow.excessive_relay, when enabled, requires an exact complete path meeting all three inclusive relay minima: function hops, module hops, and relay percent.
  • reforge.dataflow.flow_fan_out, when enabled, groups by source symbol and requires both the distinct sink-symbol and module minima.
  • reforge.dataflow.adapter_flow_bypass, when enabled, requires an explicit policy and an exact complete witness that bypasses its adapter.

All three are preview, default off, and advisory-only. Same-module forwarding, modeled or unresolved paths, unsupported semantics, generated or test sources, and truncated searches do not produce these Issues.

Search and signal thresholds

Search budgets bound deterministic traversal under [dataflow.search]: max-path-steps, max-function-hops, max-module-hops, max-paths-per-source, max-sinks-per-source, and work-budget.

Signal thresholds live separately under [dataflow.relay] and [dataflow.fan-out]. Changing a search budget never changes the rule claim.

Treat zero Issues together with coverage. partial, unsupported, and stable limitation codes identify where absence is not evidence.

Measurements and evidence

Measurements are typed values attached to Evidence. Each records a stable name, numeric value, optional numeric threshold, and unit. Evidence adds a rule, message, locations, and an optional typed Dataflow witness.

A measurement is evidence for a detector decision, not a quality score. Reforge does not combine measurements into grades, normalized health scores, or cross-rule rankings.

Issues are the baseline, gate, and SARIF decision unit. Evidence explains why an Issue exists. Prose and ordering do not change identity; measurements, thresholds, evidence-set changes, and substantive witnesses update the content fingerprint while the same typed subject keeps its Issue ID.

Coverage records the observed denominator, rule activation and maturity, and language capability limitations. An unsupported or unresolved semantic surface is never inferred as an exact edge.

The compact report does not contain the raw Codebase metric inventory. Use --metrics-output PATH for detector development or calibration. That sidecar is deliberately outside the stable report contract.

HTML report

The offline React app renders a Reforge report: Issues, nested Evidence and measurements, typed Dataflow witnesses, per-analysis coverage, suppression totals, and optional baseline comparison. It does not render raw metrics, Flow IR, arbitrary JSON extensions, or internal ontology fields.

After frontend changes run:

cd web/report-app
npm ci
npm test
npm run test:e2e
npm run build

Commit the source together with regenerated assets/report-app.js and assets/report-app.css plus their synchronized crates/reforge-output/assets copies; the HTML renderer embeds the package-local assets and requires no server or network.

Report format

The current report format uses schema_version = 27. reforge_schema::Report contains schema_version, producer, target, provenance, summary, suppression, coverage, issues, and optional baseline_comparison. Unknown fields are rejected.

Provenance records identity scheme reforge-identity-v7, the evaluated scope digest, per-analysis configuration and policy digests, and each evaluated rule’s semantic version and evaluation digest.

An Issue contains kind = advisory | policy, explicit analysis and family, typed Subject, readable prose, Evidence, an ri7-* ID, and a versioned content_fingerprint (rc7-*). Subject entities contain independent key, path, and optional symbol fields; groups contain structured entity members. Symbol keys use language, qualified owner, declaration kind, name, and signature or stable disambiguator. Prose, ordering, checkout location, comments, and line numbers do not define identity.

Evidence has an re7-* ID derived from rule and semantic anchor. Measurements, thresholds, evidence-set changes, and substantive witness changes update the Issue content fingerprint. Flow witnesses expose typed source/sink symbols, ordered steps, hop counts, and exact, modeled, unresolved, or unsupported resolution. Only all-exact, value-preserving paths can be policy witnesses.

Coverage is keyed by analysis and language. Language entries include capability receipts for syntax, symbols, lexical scopes, local def-use, direct calls, call/return composition, field flow, and dynamic dispatch. Rule entries print once with maturity, activation source, status, observations, and limitations. Zero Evidence never erases the observed denominator.

Baseline comparison maps every current or previous Issue ID to new, unchanged, updated, absent, or unknown, with an optional reason. A matching ID with a changed content fingerprint is updated. Scope, relevant configuration/policy, rule semantics/evaluation, analysis availability, or coverage changes make otherwise unprovable additions/disappearances unknown. Workspace identity mismatch is an error. Producer name and identity scheme must match, but producer versions and unrelated analysis sets may differ.

Older report formats are rejected rather than silently converted. Regenerate them with the current analyzer so their findings and Coverage describe the same analysis behavior.

Architecture

  • tools/reforge is a thin CLI and configuration boundary.
  • crates/reforge-engine owns workspace indexing, execution planning, Codebase and Dataflow analysis, evidence aggregation, and report creation.
  • crates/reforge-schema owns the public Report, stable identities, typed witnesses, coverage, and baseline comparison.
  • crates/reforge-output owns human, JSON, YAML, SARIF, and embedded HTML rendering.
  • web/report-app owns the offline HTML interface.

The engine builds one shared workspace index. Each selected source is walked, read, language-classified, and parsed once; Codebase and Dataflow consume the same indexed sources. The typed Config selects either or both analyses and owns scope, thresholds, policies, and suppressions.

The public model starts at the report. An analysis is an execution selection and a Coverage key, not a wrapper around the report:

Report
├── Coverage by analysis
│   ├── language counts
│   ├── rule execution
│   └── limitations
└── Issue
    └── Evidence
        ├── Measurement
        ├── Location
        └── optional Flow witness

Detectors produce DetectedEvidence with a semantic anchor and no internal report ID. One static RuleSpec registry supplies analysis ownership, aggregation family, output subject kind, input observation source, language support, measurements, and a rule-specific description. Families are an aggregation and identity mechanism, not an additional user workflow: after suppression, the engine groups Evidence by family and Subject into Issues; schema projection alone creates stable Evidence IDs.

The engine returns the public Report directly. Debug metrics and Flow IR take separate explicit sidecar paths and never enter the report. Flow IR is only materialized when --flow-ir-output is requested.

Contributing

Core user-facing work starts at tools/reforge and an explicit the typed Config; do not add another peer analyzer CLI for a core rule. Every new rule must declare exactly one Codebase or Dataflow owner, a namespaced family, description, supported languages, default state, measurements, and focused positive/negative tests in the rule registry.

Dataflow frontends emit the language-neutral Flow IR. Add exact edges only for semantics the frontend can prove, record dynamic/unsupported behavior as coverage limitations, and test positive, negative, partial, and unsupported cases. Stable path detectors require ordered source-to-sink witnesses, budget/cycle tests, at least five positive and five negative microfixtures, and documented real-project calibration before maturity changes.

Run cargo test --workspace --all-targets --all-features, all-target Clippy with warnings denied, both analysis self-checks, report-app unit/browser/build checks, installer tests, and docs build before review. Frontend changes must regenerate the committed embedded assets.

This project follows the repository guidelines in AGENTS.md. Keep changes small, behavior-focused, and covered by targeted tests.

Setup

Install Rust 1.85 or newer, then run:

cargo build
cargo test

For a quick end-to-end smoke test:

cargo run -p reforge-cli -- analyze . --reproducible

For reproducible machine-readable output:

cargo run -p reforge-cli -- analyze . --analysis codebase --set codebase.churn=off --reproducible --output json

Development Workflow

Use cargo fmt before review:

cargo fmt

Run tests:

cargo test

Run Clippy before larger changes:

cargo clippy --all-targets --all-features

When report formatting or schema behavior changes, include sample human, HTML, JSON, YAML, or SARIF output in the pull request description.

Report App Development

The React report app requires Node.js ^20.19.0 or >=22.12.0 and npm; CI uses Node.js 22. Vite 8 is installed from the locked frontend dependencies, so use the package scripts instead of a global Vite installation:

cd web\report-app
npm ci
npm run test
npm run build
npx playwright install chromium
npm run test:e2e

The build refreshes assets/report-app.js and assets/report-app.css, then synchronizes them into crates/reforge-output/assets. Rust embeds those files in offline HTML reports, so commit both generated asset sets with the frontend source change.

The Playwright suite generates a report with deliberately strict thresholds and opens the final self-contained HTML file in Chromium. It covers browser rendering, report interactions, and desktop/mobile layout. Failure screenshots, traces, and videos are written below target/playwright; the HTML test report is written to web/report-app/playwright-report in CI.

Documentation Site

The documentation site uses mdBook 0.5.4. Install that exact version before building or serving the site locally:

cargo install mdbook --version 0.5.4 --locked

On Windows, generate the Codebase example report and serve the site with:

.\scripts\serve-docs.ps1

Build static files into target/docs-site without starting a server:

.\scripts\build-docs.ps1

On macOS or Linux, use the matching shell scripts:

sh scripts/serve-docs.sh
sh scripts/build-docs.sh

The published documentation root is https://lylemi.github.io/Reforge/; the generated Codebase example is published at https://lylemi.github.io/Reforge/sample/. Repository administrators must set Settings > Pages > Build and deployment > Source to GitHub Actions before the Pages workflow can deploy for the first time. Keep the github-pages environment restricted to the main branch; the workflow also enforces that branch boundary for manual runs.

Tests

Unit tests live next to the modules they exercise under #[cfg(test)] or in module-specific test files included from the module. There is currently no separate tests/ directory.

Add tests for:

  • CLI parsing and default values when flags change.
  • Config precedence and discovery when configuration changes.
  • Source collection exclusions, thresholds, ordering, and report fields.
  • Detector behavior, including false-positive guards.
  • Output stability for human, HTML, JSON, YAML, and SARIF report changes.

Name tests by behavior, such as parses_output_format or groups_similar_functions.

Style

Use idiomatic Rust formatted by cargo fmt. Prefer the existing module split: cli, scan, model, detectors, evidence_analysis, workflow, and output.

Use snake_case for functions, variables, modules, and test names. Use PascalCase for structs, enums, and traits. Keep CLI flags long, descriptive, and kebab-case.

Avoid unrelated refactors in behavior changes. If a refactor is needed to make a feature safe, keep it scoped and covered by tests.

Report Compatibility

JSON, YAML, and SARIF reports are external interfaces. When fields are added, removed, or renamed:

  • Update reforge_schema::REPORT_SCHEMA_VERSION.
  • Update docs/report-schema.md.
  • Update output tests.
  • Mention the compatibility impact in the pull request.

Consumers should rely on stable Issue and Evidence IDs, typed measurements, Coverage, and typed Dataflow witnesses. The report format does not emit priority, confidence, severity, or hotspot ranking.

Commits and Pull Requests

Use Conventional Commits:

feat(codebase): detect directories with many source files
fix(report): keep JSON output stable
docs: add report schema reference

Keep descriptions imperative, lowercase, and without a trailing period. Keep commits scoped to one behavior change.

Pull requests should describe:

  • User-visible effect.
  • Validation commands run.
  • Related issues.
  • Sample human, HTML, JSON, YAML, or SARIF output when report formatting changes.

Do not commit generated outputs, dependency directories, build artifacts, or local analysis artifacts. The checked-in assets/report-app.js and assets/report-app.css bundles and their crates/reforge-output/assets copies are the sole generated-output exception because the Rust HTML renderer embeds them.