Confidence score

A number you can argue with.

Every finding carries a deterministic confidence in [0, 1] and the named signals that produced it. No model is involved. Same repository, same score — which means it can be reviewed, diffed, and trusted in CI.

0.00 0.55 0.85 1.00 base + Σ signals, clamped

Severity comes from confidence

ConfidenceSeverityMeaning
≥ 0.85blockHigh confidence. Exit code 1. Goes in the plan unless the judge says keep. Counsel reviews it as a veto, not a skip.
≥ 0.55warnProbably dead, but a signal hints at dynamic or framework use. Triaged once, then verified.
< 0.55noteLead only. Never fails CI, never sent to a model.
< 0.25droppedDefault --min-confidence. Raise it for stricter output.

Base score by kind

0.92orphan_file — no importer edges
0.88unused_export — never imported by name
0.60unused_dep — declared, never imported
0.50unreachable — private, unreferenced

Signals

Signals are added to the base and clamped to [0.02, 0.99]. Negative signals are the false-positive defenses; they are the reason a Django signal handler or a Spring bean does not fail your build.

SignalΔApplies toWhy
framework_registration_decorator−0.60exportRoutes, tasks, fixtures, commands, components are called by the framework, not imported.
framework_entry_role−0.55orphanDjango urls.py, Next.js page.tsx, Rails app/**, Spring controller/… (files with this role are skipped entirely unless they also carry a __main__ guard).
main_guard−0.45orphanif __name__ == "__main__" means it is a script, not an orphan.
module_getattr_lazy_export−0.40exportPEP 562 lazy modules resolve names at runtime.
*_named_in_string_literal−0.35bothAnother file names the module/symbol in a string: plugin loaders, settings, templates.
framework_base_class−0.35exportModels, admin classes, widgets, test cases are discovered via inheritance.
*_named_in_config−0.30bothReferenced from TOML/YAML/JSON/INI/XML/Gradle/Dockerfile/Makefile/CI.
referenced_locally−0.30exportUsed inside its own module; removing the export is a smaller change than deletion.
module_imported_whole_attribute_access_possible−0.30exportimport pkg.mod hides some attribute access from the graph. (Direct mod.name access is tracked and clears the export.)
package_init−0.30orphan__init__.py is loaded implicitly.
<lang>_name_reference_graph−0.30orphanJava, Kotlin, Scala, C#, PHP, Swift, Elixir: references are type/module tokens, so the graph is capped at warn.
<lang>_token_match_heuristic−0.30exportNon-Python export detection is token-based; never reaches block.
name_token_seen_elsewhere−0.20orphanThe file's stem appears as a token in another file — possibly a string reference or reflection.
decorated_unknown−0.20exportAny decorator may register the symbol somewhere.
listed_in_dunder_all_public_api−0.15exportDeclared public API; consumers may live outside the repo.
repo_uses_dynamic_import−0.08 / −0.10bothAny importlib/__import__/getattr in the repo lowers global certainty.
ts_regex_graph*−0.05 / −0.30TS/JSThe TS graph is regex-based; exports never reach block.
<lang>_path_resolved_graph−0.03orphanGo, Rust, Ruby, Dart, C, Lua, Perl: imports resolve to files; small discount for regex extraction.
stable_across_runsup to +0.03allFrom memory: findings that survive several runs are slightly more credible.

Worked example

{
  "id": "unused_export:svc/routes.py:health",
  "kind": "unused_export",
  "severity": "note",
  "confidence": 0.28,
  "signals": {
    "not_imported_by_name": 0.0,
    "framework_registration_decorator": -0.6
  },
  "why": "Exported symbol `health` in svc/routes.py is never imported."
}

The FastAPI route is decorated with @app.get. Base 0.88 − 0.60 = 0.28 → note. It is still reported (an agent may want to know), but it can never fail CI, never appear as a deletion in the plan, and is never sent to a model.

Compare pkg/hooks.py:maybe_dead in the fixture: base 0.88 − 0.30 (module imported whole) = 0.58 → warn. That is exactly the ambiguous case the judge and triage step exist for. The fixture's pkg/nightly.py is the other class: the graph says unused, the devil's advocate finds ops/crontab:2, and the verdict is keep.