Metadata-Version: 2.4
Name: cqa-analyzer
Version: 2.30.0
Summary: Privacy-first static code health analysis for Python packages
Author: Amit Singh
License-Expression: MIT
Project-URL: Homepage, https://github.com/AmitSinghOM/code-quality-analyzer
Project-URL: Documentation, https://github.com/AmitSinghOM/code-quality-analyzer#readme
Project-URL: Issues, https://github.com/AmitSinghOM/code-quality-analyzer/issues
Project-URL: Repository, https://github.com/AmitSinghOM/code-quality-analyzer
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click==8.3.3
Requires-Dist: rich==14.3.4
Provides-Extra: dev
Requires-Dist: build==1.3.0; extra == "dev"
Requires-Dist: pytest==9.0.3; extra == "dev"
Requires-Dist: pip-audit==2.7.3; extra == "dev"
Requires-Dist: ruff==0.8.4; extra == "dev"
Dynamic: license-file

# Code Quality Analyzer

**Prove the health of a codebase without a single byte leaving the machine.**

Code Quality Analyzer is a privacy-first static analysis tool for Python
packages, with bounded Go and TypeScript/JavaScript pilots, built for
environments where source code
cannot leave the trusted development boundary: regulated industries,
air-gapped networks, client codebases under NDA, and anyone who refuses to
ship their source to a SaaS dashboard to learn whether it is healthy.

## The privacy contract

Most quality platforms want your code on their servers. This tool inverts
that: analysis is local-only by design, and the guarantees are enforced, not
promised.

- **No network, provably.** Analysis has no network-backed integration, and
  `--offline` enforces it at runtime by denying socket and name-resolution
  operations while analysis runs — an accidental future network call fails
  the command instead of silently connecting.
- **Anonymized reports for untrusted destinations.** `--anonymize` replaces
  project, file, and function identities with opaque report-local tokens and
  strips source-derived evidence, so a report can leave the machine while the
  code's identity does not.
- **Baselines are hashes, not source.** CI baseline files contain only
  schema metadata and SHA-256 fingerprints — no paths, messages,
  identifiers, or snippets.
- **No shell, no Git, no execution.** The analyzer never invokes Git or a
  shell, and package intelligence never imports, builds, or executes project
  code. Changed-line manifests are supplied externally.
- **Honest results, enforced.** Every report carries `analysis_health` and
  an authority verdict; incomplete analysis cannot silently pass as a green
  build (`--strict` makes it fail).

See [`docs/PRIVACY.md`](docs/PRIVACY.md) for the exact data boundary.

## What it detects

- **Actionable correctness, maintainability, duplication, and package
  findings** with stable rule IDs, severities, remediation, and normalized
  locations — including cross-file **duplicate function implementations**
  (`PY-DUP-001`) detected by exact AST structure, so renamed copies still
  report and docstring changes cannot hide one
- **Data Structures & Algorithms (DSA)** patterns in Python, Go, and
  TypeScript/JavaScript
- **System Design** principles implemented in Python, Go, and
  TypeScript/JavaScript
- A compatibility **architecture signal score from 1-10**

Reports render as text, versioned JSON, or SARIF 2.1.0, and gate CI through
baselines, changed-line selection, and severity thresholds — all under the
same privacy contract.

## Architecture Signal Score Scale

| Score | Architecture-signal breadth |
|-------|-----------------------------|
| 1-2 | Very few recognized DSA or design signals |
| 3-4 | A small set of recognized signals |
| 5-6 | Moderate signal breadth |
| 7-8 | Broad signal coverage across multiple files |
| 9-10 | Very broad recognized DSA and design signals |

Architecture signal scores from 2.x are **not comparable** to 1.x ratings. Detection got stricter
and project size no longer adds score, so most projects will score lower than
they did before. See [Scoring](#scoring).

## Project Structure

```
code-quality-analyzer/
├── cqa_analyzer/
│   ├── __init__.py
│   ├── __main__.py      # CLI entry point
│   ├── baseline.py      # Hashed finding baselines and comparison
│   ├── cache.py         # Bounded local parse-artifact cache
│   ├── changed_lines.py # Bounded changed-line finding selection
│   ├── config.py        # Bounded configuration, path, and rule policy
│   ├── discovery.py     # Safe file discovery (limits, symlink guard)
│   ├── duplication.py   # Cross-file duplicate function detection
│   ├── findings.py      # Language-neutral actionable finding model
│   ├── signals.py       # Per-file signal extraction + pattern matching
│   ├── python_rules.py  # Source-located Python correctness rules
│   ├── patterns.py      # DSA & System Design pattern definitions
│   ├── go_patterns.py   # Go-idiom signal definitions for the shared catalog
│   ├── package_intelligence.py # Metadata, modules, imports, cycles
│   ├── protocols.py     # Source, parse, rule, provider, and reporter contracts
│   ├── registry.py      # Versioned plugin and capability negotiation registry
│   ├── plugins.py       # Built-in plugin assembly
│   ├── reporters.py     # Registered text, JSON, and SARIF renderers
│   ├── rule_metadata.py # Stable built-in rule catalog for standard reports
│   ├── languages/       # Built-in language adapters and rule packs
│   ├── scanner.py       # Language-neutral orchestration through plugins
│   ├── complexity.py    # Time/space complexity analyzer
│   └── rater.py         # Rating calculator (1-10)
├── tests/               # Regression tests
├── docs/                # Rule, workflow, and privacy guidance
├── .pre-commit-hooks.yaml # Published local-analysis hook contract
├── LICENSE
├── SECURITY.md
├── CHANGELOG.md
├── MANIFEST.in
├── pyproject.toml
├── requirements.txt
├── README.md
└── .gitignore
```

## Installation

Install from [PyPI](https://pypi.org/project/cqa-analyzer/) — the
distribution is named `cqa-analyzer`, the command it installs is
`code-quality-analyzer`:

```bash
pip install cqa-analyzer
code-quality-analyzer /path/to/project
```

Releases are published through PyPI Trusted Publishing with digital
attestations, so every artifact is provably built from this
repository's tagged source by CI — no maintainer-held upload token
exists.

To work on the analyzer itself, install from a source checkout:

```bash
cd code-quality-analyzer
python3 -m venv .venv
.venv/bin/pip install -e .
```

Running as a module works too: `python -m cqa_analyzer /path/to/project`.

## Pre-commit

Pin a released tag in `.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/AmitSinghOM/code-quality-analyzer
    rev: v2.29.0
    hooks:
      - id: code-quality-analyzer
```

The built-in hook runs one serial
full-repository analysis as `code-quality-analyzer . --offline`; it does not
pass staged filenames because the CLI accepts a directory. Findings are
advisory by default. Add `args: [--fail-on, error]`, or baseline/new-only
arguments, when the project is ready to gate commits.

The analyzer invocation remains local-only. Pre-commit itself may need network
access once to clone the pinned release and create its environment. See
[`docs/PRE_COMMIT.md`](docs/PRE_COMMIT.md) for trigger paths, strict and baseline
profiles, and the installation privacy boundary.

## Usage

```bash
# Analyze a project
code-quality-analyzer /path/to/project

# Show which signals triggered each match
code-quality-analyzer /path/to/project -v

# Output as JSON
code-quality-analyzer /path/to/project -f json

# Output normalized findings as SARIF 2.1.0
code-quality-analyzer /path/to/project -f sarif > results.sarif

# Select findings that overlap an externally generated line manifest
code-quality-analyzer /path/to/project \
  --changed-lines-manifest changed-lines.json

# Include time/space complexity analysis
code-quality-analyzer /path/to/project -c
```

`PROJECT_PATH` must be a directory. Pointing at a single file is rejected
rather than silently returning an architecture signal score of 1.

## Project configuration

Place `.code-quality.toml` in the analyzed project root to define deterministic
source and rule policy:

```toml
[analysis]
include = ["src/**/*.py", "cmd/**/*.go"]
exclude = ["src/generated/**"]
respect_gitignore = true

[rules."PY-COR-001"]
enabled = true
severity = "error"
```

Filters are project-relative, exclusion wins, and filtered files do not consume
candidate or file-limit accounting. The root `.gitignore` is respected by
default. Python findings can be suppressed on their reported line only with an
explicit rule ID and nonempty quoted reason, for example
`# cqa: ignore=PY-COR-001 reason="legacy API"`. Suppression reasons never enter
reports or baselines. JSON reports identify the validated effective policy with
a privacy-safe `configuration_fingerprint`.

See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for glob semantics,
validation limits, rule policy, suppressions, and compatibility boundaries.

## Incremental parse cache

Caching is explicit so analysis never writes source-derived state unless a
location is selected:

```bash
code-quality-analyzer . \
  --cache-dir ~/.cache/code-quality-analyzer/my-project \
  --offline
```

The bounded JSON cache stores only Python/Go parse artifacts. Rules, package
providers, policy, scoring, baselines, changed-line selection, reports, and
gates rerun on every analysis. Content, project-relative path, adapter, codec,
plugin API, and runtime identities participate in cache keys, so changed or
renamed files miss safely. Corrupt, stale, oversized, or incompatible entries
also become misses; cache state never reduces analysis authority.

Cache artifacts contain source-derived data and must be protected like source.
Reports expose only whether caching was enabled, never its path, keys, digests,
hit counts, or errors. See [`docs/CACHING.md`](docs/CACHING.md) for invalidation,
security bounds, warm/cold determinism, and lifecycle guidance.

## Privacy and offline options

Use `--anonymize` when a report may leave the trusted development environment:

```bash
code-quality-analyzer /path/to/project --anonymize -f json
code-quality-analyzer /path/to/project --anonymize -f sarif > results.sarif
code-quality-analyzer /path/to/project --anonymize --offline -v -c
```

Anonymized reports replace project, file, and function identities with opaque
report-local tokens; remove package/module/dependency/script names; replace
finding messages and remediation; reduce package intelligence to aggregate
counts; and remove source-derived pattern signals and complexity reasoning.
Rule IDs, locations, counts, scores, pattern names, complexity classes, and
line numbers remain so the report is still useful.

`--offline` adds runtime enforcement by denying socket connection and
name-resolution operations while analysis runs. Normal analysis is already
local and has no network-backed integration; this option makes an accidental
future network call fail the command instead of silently connecting.

See [`docs/PRIVACY.md`](docs/PRIVACY.md) for the exact data boundary and
remaining disclosure considerations.

## Options

| Option | Default | Purpose |
|--------|---------|---------|
| `--version` | – | Print the analyzer version and exit |
| `-v, --verbose` | off | Include matched files and evidence; JSON omits evidence unless enabled |
| `-f, --output-format` | `text` | `text`, versioned `json`, or SARIF 2.1.0 |
| `-c, --complexity` | off | Add experimental time/space complexity estimates |
| `--max-file-size` | 2 MB | Skip files larger than this positive byte count |
| `--max-files` | 20000 | Stop after this positive number of registered source files |
| `--redact-paths` | off | Report file names only, no directory structure |
| `--anonymize` | off | Remove project paths, metadata, and source identifiers |
| `--offline` | off | Deny socket operations while analysis runs |
| `--cache-dir` | none | Reuse bounded local parse artifacts from this directory |
| `--fail-under` | none | Exit non-zero when the compatibility architecture signal score is below 1–10; exits 5 when the score is not applicable |
| `--fail-on` | none | Exit 4 for reported findings at `warning` or `error` severity |
| `--baseline` | none | Compare findings with an existing hashed baseline |
| `--write-baseline` | none | Atomically write current finding fingerprints |
| `--new-findings-only` | off | Report and gate only findings absent from `--baseline` |
| `--changed-lines-manifest` | none | Report and gate findings overlapping a bounded line manifest |
| `--strict` | off | Exit non-zero when any requested analysis is incomplete |

`--anonymize` is stronger than `--redact-paths` and takes precedence for report
presentation. Baseline fingerprints continue to use hidden project-relative
identities, so changing either presentation option does not change CI identity.

`-f` was `--format` in 1.x. It is now `--output-format` so it no longer shadows
the `format` builtin. JSON reports include schema, analyzer, and ruleset versions
plus explicit privacy state, scoring-policy version, effective-configuration
fingerprint, and analysis authority so consumers can identify the contract,
protections, and completeness that produced a result. SARIF emits the same
baseline- and changed-line-filtered findings for standard code-scanning
consumers. Changed-line manifests are supplied externally; the analyzer never
invokes Git or a shell to derive them. JSON schema `1.11.0` records aggregate
selection metadata and whether the local parse cache was enabled; see
[`docs/CHANGED_LINES.md`](docs/CHANGED_LINES.md),
[`docs/CACHING.md`](docs/CACHING.md), and [`docs/SARIF.md`](docs/SARIF.md).
`architecture_signal_score` is the primary score field;
`rating` is a transitional equal-valued 2.x compatibility alias.

## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Analysis completed and any threshold was met |
| 1 | Architecture signal score below `--fail-under` |
| 2 | No registered-language source candidates were discovered |
| 3 | Source candidates produced no successful analysis, or `--strict` found incomplete analysis |
| 4 | A reported finding met the `--fail-on` severity threshold |
| 5 | `--fail-under` was set but the architecture signal score is not applicable (no signal-capable source analyzed) |

## Analysis Authority

Every JSON report includes `analysis_health` with source-candidate, readable,
and successfully analyzed counts; a completeness ratio; stable reason codes;
and `complete`/`authoritative` booleans. Text reports show the same
qualification before the architecture signal score.

No source candidates exit with code 2. If candidates exist but none can be
successfully parsed, analysis exits with code 3 even without `--strict`.
Partial non-strict analysis may exit successfully for inspection, but it is
always marked non-authoritative. See the versioned schema in
[`docs/report-schema-1.11.0.json`](docs/report-schema-1.11.0.json) and the decision
record in
[`docs/adr/001-analysis-authority-and-score-migration.md`](docs/adr/001-analysis-authority-and-score-migration.md).

## Use in CI

Create a baseline once after reviewing existing findings:

```bash
code-quality-analyzer . --write-baseline .code-quality-baseline.json
```

Then gate only newly introduced warning-or-higher findings:

```bash
code-quality-analyzer . \
  --baseline .code-quality-baseline.json \
  --new-findings-only \
  --changed-lines-manifest changed-lines.json \
  --fail-on warning \
  --strict \
  -f sarif > code-quality-results.sarif
```

The changed-lines manifest is generated by an external CI step. The analyzer
never invokes Git, and it continues to scan the full project for authority and
strict-mode decisions. Baseline filtering runs before changed-line selection;
see [`docs/CHANGED_LINES.md`](docs/CHANGED_LINES.md).

The SARIF artifact is emitted before the gate exit code and contains the same
selected findings used by `--fail-on`. See [`docs/SARIF.md`](docs/SARIF.md) for
the deterministic ordering, URI, metadata, and privacy contract.

Baseline files contain only schema metadata and SHA-256 fingerprints. They do
not contain source paths, messages, identifiers, snippets, or report evidence.
Baseline writes are atomic, malformed or oversized baselines are rejected, and
fingerprints remain stable when `--redact-paths` changes report presentation.
See [`docs/BASELINES.md`](docs/BASELINES.md) for workflow and review guidance.

`--fail-under` remains available as an architecture-signal compatibility
ratchet, but actionable finding gates are more explicit. Treat the score as
usable only when `analysis_health.authoritative` is true. `--strict` fails when
files cannot be read or parsed, discovery is truncated, package metadata is invalid, or requested complexity
analysis has a coverage gap. Incomplete analysis therefore cannot silently
pass as a green build.

See `.github/workflows/ci.yml` for a working example that also runs the test
suite, lint, and a dependency vulnerability scan.

## Paths

Absolute paths are never written into reports. The project is identified by its
directory name, and file paths—including skipped-file examples—are reported
relative to the project root. `--redact-paths` reduces file paths to bare names
for reports shared outside your machine.

Relative paths work fine as arguments (`.`, `../my-project`)—they are resolved
internally before discovery, but the resolved absolute path is not reported.

`--redact-paths` is path minimization, not full anonymization: findings,
package metadata, identifiers, and architecture signals can remain sensitive.
Review [`docs/PRIVACY.md`](docs/PRIVACY.md) before sharing reports. Security
issues should follow [`SECURITY.md`](SECURITY.md); do not attach proprietary
source to vulnerability reports.

---

## How Detection Works

Every pattern is defined by signals, all matched case-insensitively:

| Signal type | Matched against |
|-------------|-----------------|
| `identifiers` | An exact identifier from the AST: name, attribute, def, class, argument, import alias |
| `identifier_contains` | A substring of an identifier, for naming conventions like `OrderRepository` |
| `text` | A substring of the source **with comments and string literals blanked out**, for syntax like `dp[` or `@app.route` |
| `imports` | A substring of an imported module path |

Two rules keep the noise down:

**Literals and comments are not evidence.** A docstring saying "we should use
Dijkstra here" no longer reports a shortest-path algorithm. Comments and string
literals are blanked out before any text matching, with layout preserved so
positional patterns still match.

**Bare words match identifiers, not raw text.** `pop` matches `items.pop()` but
not `population`.

Each pattern declares `min_signals` — how many distinct signals a file must
provide before the pattern is reported. Specific patterns like `heappush` need
one. Generic ones need corroboration: a lone `visited` is not a graph
traversal, and `OrderedDict` on its own is not an LRU cache.

Run with `-v` to see exactly which signals fired, so a false positive is
reviewable rather than mysterious.

### Signals are per file

Imports are collected per file. In 1.x the import set accumulated across the
whole project, so a single `import heapq` anywhere made every file scanned
afterwards look like it used heaps — and because results depended on directory
walk order, renaming a file could change the rating.

## Scoring

```
rating = dsa_score × 0.4 + design_score × 0.5 + maturity_score × 0.1
```

**Breadth discount.** A pattern found in one file counts for 60% of its weight;
two files 80%; four or more, full weight. One incidental use is weaker evidence
than a habit.

**Size is not quality.** The 1.x "complexity bonus" grew with file count and
line count, so padding a codebase raised its rating. Size now only gates how
much of the `maturity_score` component is reachable, saturating at 2000 lines.
Past that, more code adds nothing.

**Coverage gaps lower the score.** If more than 10% of discovered files could
not be read or parsed, the rating is scaled down and reported as a lower bound
with an explicit warning.

## Scan Safety

File reads go through `cqa_analyzer/discovery.py`, which refuses to:

- read a path that resolves outside the project root, so a symlink pointing at
  `~/.aws/credentials` is skipped rather than parsed
- read a non-regular file such as a FIFO, which would otherwise block forever
- read a file above `--max-file-size`
- walk more than `--max-files` paths

Skips are counted by reason and reported. Nothing is silently dropped, so a
clean project is distinguishable from a project that failed to parse.

Excluded directories: `.git`, `__pycache__`, `.venv`, `venv`, `env`,
`node_modules`, `dist`, `build`, `site-packages`, and the usual tool caches.

## Actionable Findings

Actionable Python findings are separate from descriptive DSA and architecture
signals. Every finding includes a stable rule ID, category, severity,
confidence, message, remediation, and a one-based project-relative source
location. JSON reports include both `findings` and an aggregate
`finding_summary`; terminal reports show an **Actionable Findings** table.

The built-in Python rules detect mutable function defaults, broad exception
handlers, silently swallowed exceptions, directly unreachable statements,
functions above measured cyclomatic or cognitive complexity limits, oversized
functions, excessive parameter lists, boolean mode proliferation, known
blocking calls in async functions, locally unmanaged file/temporary
resources, and cross-file duplicate function implementations. Duplication
(`PY-DUP-001`) compares docstring-stripped bodies, parameter lists, and
return annotations by exact AST structure: renamed or re-decorated copies
still report, trivial functions never do, and only the outermost of nested
duplicates reports. Rule enablement and severity can be configured, and valid
same-line suppressions
require an explicit rule ID and quoted reason. See
[`docs/RULES.md`](docs/RULES.md) for rule behavior and remediation examples and
[`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for policy details.

Files are parsed once for signal extraction, actionable Python rules, package
intelligence, and optional complexity analysis. Malformed files emit no
semantic findings and remain visible through analysis health.

## Package Intelligence

Package intelligence is passive: it does not import, build, or execute project
code. Every normal scan now reports:

- Parsed `pyproject.toml` name, Python requirement, build backend, dependencies,
  optional dependency groups, and console scripts
- Detected `src` or flat package layout and source roots
- Statically configured setuptools PEP 420 namespace modules from safe,
  explicit discovery roots and prefixes
- First-party modules and their local import graph
- Circular import groups
- Console scripts that target missing local modules
- Literal `__all__` exports with missing bindings or duplicate names
- Missing literal static setuptools package-data source targets

Invalid TOML produces `PY-PKG-003` and makes `--strict` fail. Circular imports
produce `PY-PKG-001`; invalid console-script module targets produce
`PY-PKG-002`; missing and duplicate literal public exports produce
`PY-PKG-004` and `PY-PKG-005`. Dynamic or ambiguous `__all__` declarations are
conservatively skipped. Configured PEP 420 discovery accepts only setuptools
metadata with namespace discovery enabled, safe project-relative `where` roots,
and nonempty exact or `prefix.*` includes. Custom backends, remapping, excludes,
complex globs, and ambiguous roots retain conventional discovery without
executing build hooks. Literal package-data validation is limited to exact
package keys and safe, non-glob paths when setuptools is the only declared build
requirement and no custom setup file, backend path, command class, or package
remapping is present. It checks source-tree regular-file existence with metadata
operations only; wildcard declarations, generated files, and built-artifact
contents remain out of scope. Test-only directories without a package
initializer are excluded from unconfigured flat-layout package modules. See
[`docs/RULES.md`](docs/RULES.md).

TOML parsing uses the standard-library `tomllib` parser; the analyzer
requires Python 3.11 or newer.

## Complexity Analysis

Complexity output is an **experimental static estimate**, not an authoritative
Big-O guarantee. Use its assumptions, reasoning, and confidence to prioritize
manual review; do not use inferred Big-O alone as a CI quality gate.

Use the `-c` flag to include time/space complexity analysis:

```bash
code-quality-analyzer /path/to/project -c
code-quality-analyzer /path/to/project -v -c  # verbose adds reasoning
```

Handled correctly as of 2.0:

- **`async for` counts as a loop.** Async-heavy code used to report `O(1)`.
- **Early exit is scoped to its own loop.** A `break` in an inner loop no
  longer marks the outer loop as having an early exit. A `return` still does,
  from any depth.
- **Nested definitions are separate units.** An inner function's loops no
  longer inflate the enclosing function's depth, and its self-calls no longer
  count as the parent's recursion. Each nested function is analyzed on its own.
- **Recursion inside a loop** is classified as `fan_out` rather than linear.
  The branching factor is data-dependent, so it reports `O(n)` over visited
  nodes with reduced confidence instead of claiming certainty.

### Confidence Score

The confidence score indicates how reliable the complexity estimate is.

**Starting point:** 80%

| Condition | Deduction | Reason |
|-----------|-----------|--------|
| Recursion without memoization | -20% | Hard to tell O(n) from O(2^n) without runtime analysis |
| Recursive call inside a loop | -20% | Branching factor depends on the data |
| Deep nesting (>2 loops) | -10% | Complex control flow makes static analysis less reliable |
| No type hints on parameters | -10% | Can't infer if input is a collection or its size relationship |

**Minimum:** 30%

**Interpreting confidence:**
- 80%+ → High confidence, estimate is likely accurate
- 60-80% → Medium confidence, estimate is reasonable but verify manually
- 30-60% → Low confidence, treat as rough estimate only

---

## What It Detects

### DSA Patterns (24 patterns)

**Data Structures:**
- Hash maps (Counter, defaultdict)
- Sets and set algebra
- Trees (binary, general)
- Linked lists
- Queues and stacks (deque)
- Heaps and priority queues
- Trie/prefix tree
- Segment tree
- Fenwick/Binary Indexed Tree
- Bloom filter

**Algorithms:**
- Sorting
- Binary search
- Graph traversal (BFS/DFS)
- Dynamic programming/memoization
- Union-Find/Disjoint Set
- Topological sort
- Shortest path (Dijkstra/Bellman-Ford/A*)
- Minimum spanning tree (Kruskal/Prim)
- Backtracking

**Techniques:**
- Sliding window
- Two pointers
- Monotonic stack
- Interval operations
- Manual LRU cache

### System Design Patterns (14 patterns)
- API design (FastAPI, Flask, Django, Starlette)
- Database ORM
- Caching layers
- Message queues
- Factory, Singleton, Repository patterns
- Dependency injection
- Error handling
- Logging
- Authentication/Authorization
- Testing
- Microservices/service clients
- Configuration management

Python receives actionable rules, package intelligence, architecture signals,
and experimental complexity analysis. The Go pilot discovers `.go` files,
preserves import aliases, emits `GO-COR-001` for discarded errors from a
narrow set of imported standard-library calls, extracts Go-idiom DSA and
design signals from blanked source (`container/heap`, `sort.Search`,
corroborated BFS/DFS, `net/http`/gRPC API design, `database/sql`/GORM,
message queues, `sync.Once` singletons, and more), and passively aggregates
multi-file packages plus local module import edges from `go.mod`. It never
invokes Go tooling. Go patterns reuse the shared scoring catalog IDs, so
mixed projects aggregate signals across both languages under one score.
Python and Go findings share the same report, baseline,
privacy, offline, and CI-gate contracts. JSON `project_analyses` entries expose
provider results normally and health-only projections under `--anonymize`.
See [`docs/RULES.md`](docs/RULES.md).

The TypeScript/JavaScript pilot covers `.ts`, `.tsx`, `.js`, `.jsx`,
`.mjs`, and `.cjs` with the same bounded, no-toolchain discipline: it
blanks comments, strings, and template literals (interpolations included,
so literals are never evidence), extracts bounded identifiers and import
specifiers by regex, emits `TS-COR-001` for empty catch blocks, and
passively reads the root `package.json` to flag imported-but-undeclared
dependencies (`TS-PKG-001`) and invalid manifests (`TS-PKG-002`).
Workspace (monorepo) manifests skip drift analysis, node builtins and
path aliases are never flagged, and generated output directories
(`.next`, `dist`, `build`, `coverage`, and friends) are excluded from
discovery. It never invokes `node`, `tsc`, or a package manager. TS/JS
architecture signals match ecosystem idioms (`new Map`/`new Set`,
memoization, express/fastify/NestJS/tRPC API design, Prisma/TypeORM
data access, redis/react-query caching, kafkajs/bullmq queues,
jsonwebtoken/next-auth authentication, vitest/jest/playwright testing)
through the same shared scoring catalog, so full-stack projects
aggregate one score across all three languages.

The architecture signal score covers Python and Go signals. A project where
no signal-capable source was successfully analyzed reports the score as
**not applicable** — `null` in JSON with an explicit
`architecture_signal_scope` field — rather than a misleading floor value,
and `--fail-under` exits with code 5 instead of silently passing or failing.
[`docs/ROADMAP.md`](docs/ROADMAP.md) tracks what comes next: a
TypeScript/JavaScript pilot and decision-gated Go duplication depth.

## Development

```bash
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest        # tests
.venv/bin/python -m ruff check .  # lint
.venv/bin/python -m pip_audit     # dependency vulnerabilities
```

The test suite carries a regression test for each detection and safety bug
fixed in 2.0, including symlink escape, FIFO reads, cross-file import leakage,
and the complexity analyzer's scope handling.

## License

[MIT](LICENSE)
