All notable changes to AI-SLOP Detector will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Split the Python analysis core into focused scoring, topology, and project aggregation modules while preserving the existing CLI and result contracts.
- Project reports now expose a finding summary, severity distribution, and scan coverage envelope in JSON, text, Markdown, and Rich output.
--include-testsexplicitly includes only the built-in test-file exclusions; user-configured ignores and artifact exclusions remain intact.- Known source files outside Python, JS/TS, and Go are reported as
unsupportedcoverage rather than silently disappearing from scope. - A labeled strictness corpus covers true alpha-renamed copies, symmetric comparators, declarative factories, Protocol markers, and valid context manager semantics.
- Rust discovery now emits root-relative paths and is parity-checked against Python discovery before use on Windows and other platforms.
- Excluded-file evidence preserves exact totals and reason counts while capping detailed paths at 200 entries, preventing dependency trees from inflating machine-readable reports.
- Self-calibration documentation now states the actual boundary: history and automatic milestone application are repository-local operational adaptation, not independent external validation.
- Incompatible ML artifacts now report an explicit
ml_scoring=unavailablecapability state with schema evidence instead of failing silently. - Dependency hygiene distinguishes undeclared imports, requirements-only declarations, optional imports, and unavailable runtime dependencies.
- Clone and placeholder checks no longer flag the covered intentional patterns; true copied logic remains detectable.
- A
cleanweighted deficit status no longer hides independent pattern findings from project-level human-readable output.
472 passedin the AI-SLOP-Detector Python suite.- CuraFrame dogfooding:
186 passed in 17.02sin an isolated environment. - P4 output-contract scripts for test exclusion, coverage, and finding visibility all pass. These checks do not establish an aggregate accuracy rate or independent external validation.
- Packaging metadata cleanup:
pyproject.tomlnow uses SPDX string form (license = "MIT")- deprecated license classifier removed to match current setuptools guidance
- VS Code extension workflow reliability:
Refresh Issuesnow performs a real workspace re-scan instead of only repainting the tree- workspace scans replace stale cached file results, so renamed or removed files no longer linger in the sidebar
- workspace issue selection now opens the exact file path rather than matching by basename only
- Quick Fix actions now write
ignoreandphantom_import_allowlistentries into.slopconfig.yamlwith duplicate-entry protection - command/view activation was expanded so the extension wakes reliably from the Command Palette and sidebar before a supported editor is open
- Default ignore coverage now skips Claude worktree snapshots under
.claude/**so transient agent scratch trees do not pollute project scans. - DDC runtime accounting now computes the numerator from runtime-visible usage
only, so a library imported at runtime is not undercounted just because the
same package also appears in a
TYPE_CHECKINGblock. - Inflation jargon scanning now ignores standalone quoted literals inside vocabulary tables and constant lists; storing a buzzword lexicon is no longer treated as rhetorical inflation.
- JS/TS fallback callback-hell detection now counts structural control-flow / function blocks instead of raw braces, and AST depth now ignores object/array literals. React / TSX render trees and style objects are no longer treated as nested callbacks.
nested_complexitynow fires only when both depth and cyclomatic complexity exceed their thresholds, matching the strictness semantics used elsewhere.- Tiny one-line helpers with a one-line noun-phrase docstring are now treated as neutral rather than docstring inflation.
- Phantom-import discovery now scans first-level monorepo package roots (for
layouts like
backend/app/...) and understands package/import alias pairs such asgrpcio -> grpcandpyyaml -> yaml. - Clone detection now requires a mutual-similarity clique plus a bounded size ratio instead of using a looser connected-component chain, reducing verifier / orchestrator false positives.
- Property-only accessor groups (
@propertysummary getters) are exempted from clone-cluster findings. - Self-dogfood hotspot pressure dropped materially after the boundary fixes:
AI-SLOP-DETECTORself-scan moved fromdeficit_files = 8to3, andweighted_deficit_scoreimproved from9.3892to6.4186.
python -m pytest tests/test_docstring_inflation.py tests/test_patterns/test_patterns.py tests/test_fp_reduction.py tests/test_js_analyzer.py tests/test_ddc.py tests/test_inflation.py tests/test_core.py -qpython -m slop_detector.cli scan D:\\Sanctum\\AI-SLOP-DETECTOR --project --jsonpython -m slop_detector.cli scan D:\\Sanctum\\alecta-stock --json
- Strict same-file duplicate detection now surfaces in cleanup output as
same_file_exact_duplicate, sosweep dupesand cleanup JSON can catch the exact-duplicate blind spot fixed in issue#45. - The clone metric now detects files with exactly four near-identical helper
functions instead of silently skipping them due to the previous
MIN_FUNCTIONS_FOR_CLONE=5threshold mismatch.
- Dead-code cleanup semantics now require real dead-code evidence (placeholder-only file or explicit dead-code pattern) instead of using generic high-deficit files as dead-code candidates.
- Clone wording is now consistent across code, renderers, cleanup output, and
docs:
exact_duplicate_pair= exact same-file duplicates after local-name normalizationfunction_clone_cluster= near-identical function clusters
operations.pywas split further into focused helper modules:operations_payloads.pyoperations_cleanup.pyoperations_architecture.py- with the earlier
operations_manifest.pyandoperations_render.py - while keeping
slop_detector.operationsas a compatibility façade.
- Claude Code skill guidance now uses the canonical product surface:
scan,review,pulse,sweep,explain,verify-governance, andmcp, instead of the older/slop*-centric workflow framing. - README, roadmap, and development docs now reflect the current clone surfaces, operations split, and agent workflow model.
- Human summary hides internal algorithm names. The Project Summary
coherence row no longer leaks
vr_structural (exact MST); it now readsStructure Coherence: 85% (Higher is more cohesive)with a plain coverage note (full/sampled (large project)) across the rich, text, and markdown renderers. Centralized inrenderer_glossary.coherence_display()(OSOT).
- Machine output is now patch-complete (AI-agent friendly). Project-level
JSON / agent route / MCP output gains two additive keys:
next_steps— the same deterministic, prioritized action plan humans see (top concern, recommended sweep command, file to start with).metric_guide— per-metricvalue/ healthydirection/ plainmeans, so an agent reading JSON gets the same semantics as a human reader.
- The JSON
coherence_levelvalue (vr_structural/vr_structural_approx) is unchanged — only the human-facing label was translated. New keys are additive and backward-compatible; no existing key was renamed or removed.
- README entry point rewritten benefit-first: a three-line value proposition
with no internal mechanism, a de-jargoned "What Is It?" list (technical terms
kept in parentheses), plus two new sections — "Why Not Just Use a Linter?"
(honest comparison table vs ruff / pylint / ESLint / SonarQube, with
Partialmarked where they overlap) and "When NOT to Use This". docs/HOW_IT_WORKS.md: added a "What the Acronyms Mean" glossary that decodes every diagram (LDR, Inflation/ICR, DDC, Purity, GQG, Deficit Score, SR9), reusing the exact wordings the CLI prints (renderer_glossary.py).docs/CONFIGURATION.md: added plain-language comments to every key in theadvanced:block and glossed GQG / LEDA in the config-validation section.
- Documentation only. No code, scoring math, public API, MCP, or npm typed
contracts were changed.
MATH_MODELS.md(intentionally technical) was left as-is.
Human-friendly output (analysis -> action)
- Project and per-file reports now render a metrics table with
Value,Healthy Direction, andWhat It Meanscolumns plus a deficit-band legend (CLEAN <30 | SUSPICIOUS 30-50 | INFLATED 50-70 | CRITICAL >=70), so scores are interpretable without prior knowledge (addresses the "no way to gauge the scores" feedback). - Deterministic, rule-based
Next Steps: each report names the top concern, recommends the matching cleanup command (sweep unused-deps/dead-code+dupes), and points at the highest-priority file plusreviewscoping. - A single
renderer_glossarymodule is the source of truth for metric labels, healthy direction, plain-language meaning, and health bands; the rich, text, and markdown renderers all consume it for identical wording.
VS Code extension
- Data layer now consumes the
ai-slop-detectornpm wrapper API and typed contracts instead of hand-rolledchild_processcalls; all backend execution flows through the wrapper (scan/review/pulse/sweep). - New webview panels: 4D +
deficit_breakdown(why-not-0.0), confidence-ranked cleanup plan, pulse health dashboard, and diff-aware changed-code review. - Getting-started walkthrough, state-aware empty states, context-key view menus,
and a domain-profile setting with
enumDescriptions. - npm wrapper gained
options.cwd,runTextCommand, and typed function declarations so editor/agent consumers are fully typed.
P0 self-dogfood debt reduction
operations.pycleanup-family assembly was split into smaller helpers for:- dead-code collection
- duplicate collection
- manifest hygiene
- stale suppressions
- boundary review
operations.pymanifest hygiene paths now use smaller Python / JS helper stages instead of monolithic scanners.operations.pytext and markdown cleanup renderers were split into smaller summary/target/issue formatting helpers.cli_init.pyinit orchestration was decomposed into smaller helpers for:- option resolution
- domain resolution
- preview handling
- existing-config skip handling
- YAML load / merge support
cli_init.pydomain detection and language counting now use dedicated collection/scoring helpers rather than single monolithic functions.
P0 self-dogfood hotspot reduction
- self-dogfood
pulseweighted deficit score improved from21.3221to18.9637after refactoringoperations.pyandcli_init.py. cli_init.pydropped out of the top self-dogfood hotspot set and now scans ascleanat the file level.operations.pydead-code heuristics now avoid treating obvious CLI / script entrypoints as placeholder-only files.operations.pyno longer importstomlidirectly in the scoring surface; runtime import fallback is now used to avoid phantom-import findings on the compatibility path.
Dead-code family semantics
sweep dead-codenow requires real dead-code evidence (a placeholder file or a dead-code pattern such aspass_placeholder/not_implemented/interface_only_class) instead of any highdeficit_score >= 30. Live high-deficit files (e.g.analysis_cache.py,api/server.py) are no longer mislabeled; self-dogfood dead-code dropped from 58 to 10 candidates.
Adaptive init no longer drops hand-written config
--force-initcombined with--apply-init-suggestionspreviously overwrote.slopconfig.yamlwith the template and then merged onto that template, losing hand-written keys. The pre-existing config is now captured before any overwrite and used as the adaptive merge base.
unused-deps false positives
- Standard-library modules (
abc,ast,collections, ...) are no longer reported asundeclared_import. Detection usessys.stdlib_module_nameswith asysconfig-based discovery fallback for Python 3.8 / 3.9. - The unused-dependency check now covers main
[project.dependencies]only;optional-dependencies(dev/test tools likeblack,mypy,pytest) are no longer flagged as unused. Self-dogfoodunused-depsdropped from 64 to 20.
Adaptive --init onboarding flow
--adaptive-initadds a second-stage repository signal scan on top of the existing baseline.slopconfig.yamlgenerator.--init-previewprints adaptive suggestions without writing config.--apply-init-suggestionsopt-in merges bounded suggestions into a new or existing.slopconfig.yaml.- Adaptive signal collection now gathers:
- manifest presence
- language counts
- noise directories
- Python complexity candidates
- architecture layout markers
- cleanup markers
NPM thin wrapper surface
- Added a dedicated
npm-wrapper/package for Node-first distribution. - Added a thin launcher:
bin/ai-slop-detector.js
- Added wrapper runtime contract tests and CI coverage.
- Added explicit install story for:
npmpnpmyarnbun
- Added package-local wrapper README and backend prerequisite documentation.
- Added version-pinned TypeScript contract exports at
ai-slop-detector/typesforscan,review,pulse,sweep, andexplainJSON outputs. - Added a programmatic Node API surface at the package root for:
scanProjectreviewChangescomputeHealthrunCleanupFamily
- Added an agent workflow guide covering JSON-first review, cleanup, health, and MCP-assisted usage patterns.
Local impact and opt-in telemetry
- Added repo-local impact tracking commands:
slop-detector impact enableslop-detector impactslop-detector impact disable
- Impact snapshots are stored in gitignored
.slop-detector/impact.jsonand summarize trend deltas across repeated runs. - Added telemetry control commands:
slop-detector telemetry statusslop-detector telemetry enableslop-detector telemetry disableslop-detector telemetry inspect --example
- Added anonymized telemetry payload construction and local queueing.
- Added inspect-first telemetry mode:
AI_SLOP_DETECTOR_TELEMETRY=inspect- prints a real payload without queueing or sending it
- Adaptive suggestions stay conservative and evidence-backed:
- ignore suggestions skip patterns already covered by defaults/profile rules
god_function.domain_overridessuggestions are exact-name and capped- architecture remains
stay_disabledunless layered evidence is strong
- Existing-config init flow remains idempotent by default and only merges adaptive changes with explicit opt-in.
- README, CLI usage, and configuration docs now describe baseline init, adaptive preview, and explicit merge as distinct flows.
- npm wrapper documentation now states explicitly that Node is a transport surface over the Python core, not a second implementation.
- Impact and telemetry surfaces are kept out of the scoring path: scoring remains deterministic, while adoption observability is opt-in and separately controlled.
[3.8.1] - 2026-06-04 — Absorption Chapter: Cleanup Confidence, Manifest Hygiene, Architecture Review
Absorption chapter: cleanup planning and architecture review
- Cleanup-family output now extends each
issues[]item with:confidenceaction_classevidence
- Cleanup confidence reuses existing signals instead of inventing a detached
model:
deficit_score- churn
- coverage
- cleanup-local evidence
unused-depsnow includes project-level manifest hygiene for:pyproject.tomlpackage.json
- New cleanup issue types:
manifest_unused_dependencyundeclared_import
boundary-violationsnow supports an opt-in architecture review path with a layered preset and explicitlayer_boundary_violationfindings.
- Architecture review remains cycle-only by default; layered boundary rules are
opt-in through
.slopconfig.yaml. - Layered preset evidence now includes matched importer/importee patterns and the exact allow/forbid rule that triggered the finding.
- README, CLI, architecture, and configuration docs now describe the
v3.8.1operational surface.
Canonical CLI verbs
slop-detector scan <target>is now the preferred stable analysis entry point.slop-detector review <target>is now the preferred changed-code review surface.slop-detector pulse <target>is now the preferred repository health surface.slop-detector sweep <family> <target>is now the preferred cleanup-family surface.- Legacy command forms such as
audit,health, and direct cleanup-family verbs remain supported for compatibility.
Dogfood hotspot prioritization stability
prioritization.pyno longer assumes every ASTbodyis a list while estimating executable lines for coverage overlays.healthandauditnow survive lambda-heavy files and other non-list AST body shapes during self-analysis.
- README and CLI docs now present the canonical CLI surface first and treat earlier mixed flag/verb paths as compatible legacy entry points.
Fail-closed governance verification
slop-detector verify-governanceverifies.cr-ep/governance_record.jsonby recomputing the canonical record hash and failing closed on tamper.- The gate also fails closed on policy violations such as
halt_count > 0ortrust_tier == "UNTRUSTED". - Governance verification is isolated from scoring so mathematical metrics and enforcement policy remain separate layers.
Formal docs
docs/MATH_MODELS.mdnow carries the snapshot audit boundary used by the scoring model.docs/GOVERNANCE.mddocuments the governance artifact contract and verification command.
- README, architecture notes, CLI usage, and release notes now describe the governance verification surface and the math/enforcement split.
Structural scaling
core.pynow caps exact structural coherence at a configurable ceiling and falls back to a deterministic approximation above that limit.- CLI flags expose the exact-ceiling and above-ceiling topology mode so the behavior is user-controlled instead of implicit.
Inline suppression
- Inline directive parsing now supports
# slop-disable-next-line,# slop-disable, and# slop-enablewithpattern_idorall. - Suppressed issues are recorded in an audit ledger and surfaced in terminal, markdown, rich, and CI/gate output.
Repeated-run cache
- Python file analysis results can now be reused through a SQLite-backed cache.
- Cache entries are invalidated by file content, metadata, config fingerprint, and engine version drift.
Priority hotspots
- Project scans now combine deficit, git churn, and coverage gap to rank files by "fix first" priority.
- Hotspot reasons are exposed in human-readable form for agent and reviewer use.
Agent-native surface
- The FastAPI API now exposes
/agent/schema,/agent/file, and/agent/projectfor structured consumers. - Agent responses bundle summaries, suppression metadata, hotspots, and
polyglot analysis results without changing the existing
/analyze/*routes.
Release documentation sanity
- README, release notes, architecture docs, and API docs now describe the current integrated release rather than the earlier 3.7.7 baseline.
Cross-language project aggregation completeness
core.py—analyze_project()now aggregates Python, JS/TS, and Go results into a singleall_resultscollection before computingtotal_files,deficit_files,clean_files,avg_deficit_score,weighted_deficit_score, andoverall_status.- JS-only and Go-only projects no longer fall through the empty-project path and
get mislabeled as
cleanwithtotal_files = 0. - Added language-neutral helpers for project aggregation so Python
SlopStatusenum values and JS/Go string statuses are normalized through one boundary.
Repo-relative ignore matching on absolute paths
core.py—_should_ignore()now accepts an optionalrootand matches both absolute and repo-relative normalized paths. Patterns such astests/**,**/*.generated.py, andsrc/**/*.generated.pynow behave consistently during project scans.analyze_project(),_analyze_js_files(), and_analyze_go_files()now passroot=project_path_objinto_should_ignore()so all three language paths use the same ignore semantics.
Project metric consistency
core.py—avg_ddcnow uses the Python-result count as its denominator (max(1, len(results))) instead oftotal_files. This restores consistency withavg_inflation, which is Python-derived only, and prevents JS/Go file counts from artificially depressing DDC averages.
ML pipeline reproducibility and report correctness
ml/pipeline.py—TrainingSamplenow preserves generated source incode._build_dataset()reusessample.codeinstead of regenerating synthetic files, eliminating hidden drift between labeled sample creation and feature extraction._train_from_dataset()centralizes dataset training, report writing, and fail-fast validation.- Training now raises
ValueErrorwhen only one class remains after filtering, instead of proceeding into an invalid one-class training run. PipelineReport.n_samples,n_train, andn_testnow reflect usable feature rows rather than originally requested raw sample count.
tests/test_core.py— regression tests for:- JS/Go-inclusive project aggregation
- JS-only project status
- repo-relative ignore behavior on absolute paths
- recursive generated-file glob ignores
tests/test_ml_pipeline.py— regression tests for:- synthetic sample code preservation
- no-regeneration dataset building
- usable-sample report counts
- one-class fail-fast behavior
Per-file deficit_breakdown (SLOP-003)
core.py— new_compute_deficit_breakdown()attributes a non-zero file score to its source dimensions via log-loss share allocation. Emits five penalty fields (ldr_penalty,inflation_penalty,ddc_penalty,purity_penalty,pattern_hits) plustotal. Penalties sum tototalwithin 0.01 whendeficit_score < 100.core.py—_calculate_slop_statussignature extended to return the breakdown alongside(score, status, warnings).models.py—FileAnalysisgains adeficit_breakdown: Dict[str, float]field;to_dict()includes it when populated.- README "Scoring Model" section now documents the five-field shape and the sum-to-total invariant.
coherence_level documentation (SLOP-002)
- README "Scoring Model" now lists the actual emitted values (
vr_structural,none) — the v3.7.5 audit listedmst_persistence/not_applicable, but those names are not present in the code. Verify-first applied.
60-Second First Run block (SLOP-005)
- README gains a top-level "60-Second First Run" section that produces a working JSON result on any folder of Python without requiring
--init. - Quick Start and 60-Second blocks both recommend
--output <path>over> pathredirection (PowerShell BOM safety; SLOP-001).
--init is idempotent (SLOP-006)
cli_commands.py:_run_init— re-running--initon an initialized project now prints[*] .slopconfig.yaml already initialized.and exits 0 (previously exited 1). CI scripts that call--initunconditionally no longer fail on repeat invocations.--force-initretains the explicit overwrite semantic.
tests/test_core.py—test_calculate_slop_status_thresholdsupdated for the new 4-tuple return; newtest_deficit_breakdown_attribution_on_clean_filecovers field shape, conservation, andto_dictround-trip.tests/test_domain_init.py—TestInitIdempotency::test_rerun_returns_zerocovers SLOP-006 acceptance.- Full suite: 323 passed, 5 skipped (was 321 passed, 5 skipped).
- SLOP-001 was filed against v3.7.5 but the
--outputflag and UTF-8 (no BOM) write path already existed in that release. v3.7.6 keeps the code path unchanged and only adds documentation that points users away from shell redirection. - SLOP-004 (per-file JSON schema) is deferred —
docs/SCHEMA_VALIDATION.mdalready covers input-config validation; a separate output-shape schema requires more design work and was not material to the immediate UX gap.
[3.7.5] - 2026-05-20 — False Positive Patch: Flat-Module Sibling Discovery + phantom_import_allowlist
phantom_import false positives on flat-module projects (no pyproject.toml / __init__.py)
patterns/python_imports.py—PhantomImportPattern: added__init__(allowlist)parameter; modules listed inphantom_import_allowlistinside.slopconfig.yamlare now respected and skip phantom detection.patterns/python_imports.py—_discover_sibling_modules(): new helper that collects stem names of all.pyfiles in the scanned file's own directory. Used as an additional skip set incheck()so that sibling modules in flat projects (e.g.cas_parser.py,cas_html.py) are never flagged as phantom regardless of whether a project root is found.config.py— addedphantom_import_allowlist: []toDEFAULT_CONFIGandget_phantom_import_allowlist()getter.patterns/__init__.py—get_all_patterns()now acceptsphantom_import_allowlistand forwards it toPhantomImportPattern.core.py—SlopDetector.__init__passesphantom_import_allowlistfrom config toget_all_patterns().
Root causes addressed
_discover_project_packagesonly recognised Python packages (directories with__init__.py); single-file modules in flat projects were invisible to it.phantom_import_allowlistwas a documented.slopconfig.yamlkey that was parsed into the config dict but never read byPhantomImportPattern.
Effect on CAS audit (Flamehaven Code Audit Standard)
Flat-module project cas_*.py with project-local imports (from cas_parser import ...): phantom_import false positives eliminated. overall_status for the CAS package corrected from suspicious to clean.
tests/test_fp_reduction.py— 3 new regression tests:test_sibling_module_not_flagged_as_phantom,test_phantom_import_allowlist_respected,test_discover_sibling_modules_returns_stems.
Pattern accuracy — 6 false-positive sources eliminated
patterns/placeholder.py—EllipsisPlaceholderPattern: added@abstractmethodguard;def method(self) -> None: ...in an ABC no longer firesellipsis_placeholderpatterns/placeholder.py—InterfaceOnlyClassPattern._count_placeholder_methods:@abstractmethoddecorated methods are now excluded from the placeholder count; a pure ABC with N abstract stubs no longer triggersinterface_only_classpatterns/placeholder.py—ReturnNonePlaceholderPattern: added@abstractmethodguard +_has_optional_return()helper;return Nonein a method annotated-> Optional[T]or-> T | Noneis the Null Object pattern, not a placeholder stubmetrics/stub_density.py—calculate_stub_density():@abstractmethodfunctions are filtered before_find_largest_clone_group; an ABC with N identical abstract stubs no longer generates a spuriousCRITICALclone clusterpatterns/python_imports.py—_add_dep_names(): PEP-508 extras specifiers (psycopg[binary]) are now stripped via explicit regex before canonicalisation; guarded imports for properly declared optional dependencies are no longer flagged as phantompatterns/python_clones.py—_is_dispatcher_pattern(): Signal 3 added — if the file contains a module-levelapporrouterassignment (FastAPI / Flask route file), the entire file is exempt from clone-cluster flagging
Additional accuracy fixes
metrics/inflation.py—InflationCalculator._scan_for_jargon(): word matching now uses\bregex boundaries; previously"neural"would match insideneural_network_trainingidentifier namesmetrics/inflation.py—academicjargon list:theorem,proof,lemmaremoved; these are primary domain vocabulary in formal-methods and governance code, not AI slop signalsmetrics/inflation.py—_MIN_DENSITY_LINES = 15: jargon density is now computed againstmax(logic_lines, 15); prevents a single jargon word in a 7-line file from scoring the same as 2 hits in a 14-line filepatterns/python_complexity.py—GodFunctionPattern: pure line-length violations where complexity < 4 are no longer flagged; declarative setup code (argparse subcommand tables, config blocks) is computationally simple and should not triggergod_function
tests/test_fp_reduction.py: 6 regression tests added (cases ⑩–⑮), one per fixed FP source; all 324 tests passtests/corpus/placeholder_code.py: ABC regression fixtures appended (abstract ellipsis stubs, Optional return, concrete NullImpl)tests/test_inflation.py:test_justified_jargonupdated to use standalone word in comment; validates word-boundary detection
docs/PATTERNS.md: version header updated; descriptions corrected forellipsis_placeholder,return_none_placeholder,interface_only_class(severity HIGH, threshold 50%),function_clone_cluster(algorithm: JSD < 0.05, not Jaccard 0.85),phantom_import(extras handling)
config.py: pydantic imports moved insidetry/except ImportError; when pydantic is absent_validate_yaml_config()returns immediately — package imports cleanly in stripped environments (e.g.pip install ai-slop-detectorbefore deps resolve)tests/test_api_models.py: guard changed fromimportorskip("pydantic")toimportorskip("fastapi"); pydantic is now a base dep so the old guard no longer skipped the test, causing a collection error when fastapi (api extra) was absent
ci.yml(Docker job): Docker Hub login now usescontinue-on-error: true; push step conditional onsteps.docker_login.outcome == 'success'— missingDOCKER_USERNAME/DOCKER_TOKENsecrets no longer fail the buildci-gate-fixed.yml: install pinned to"ai-slop-detector>=3.7.3"to prevent the self-referential quality gate from resolving to the broken v3.7.2 PyPI package
Core — data boundary validation
config.py:_validate_yaml_config()validates critical sections of.slopconfig.yamlbefore merging — Pydantic schemas_WeightsSchema(range[0.0, 1.0]per weight),_DomainOverrideSchema(str pattern, int thresholds≥ 1),_GodFunctionSchema— Bad user config (e.g.weights.ldr: "hello",complexity_threshold: "high") raisesValueErrorwith exact field path at load time, before it can reach the GQG formulamodels.py:__post_init__range guards on computed metric results —LDRResult: clampsldr_scoreto[0, 1]withWARNINGlog — protectsmath.log()in GQG scorer —InflationResult: clampsinflation_scoreto[0, ∞)— prevents negative score artefacts —DDCResult: clampsusage_ratioto[0, 1]withWARNINGloghistory.py:HistoryEntry.__post_init__sanitises all numeric fields before SQLite insertion — Clampsdeficit_score ≥ 0,ldr_score / ddc_usage_ratio ∈ [0, 1],n_critical_patterns / pattern_count ≥ 0— Validatesfired_rulesas parseable JSON at write time (not silently on read); LEDA calibration grid search inputs are now structurally guaranteed
VS Code Extension v3.7.2
schema.ts(new, 185 L):ISlopReport,ILdrResult,IInflationResult,IDdcResult,ISlopPatternTypeScript interfaces mirroringFileAnalysis.to_dict()contract;ParseResult<T>discriminated union (ok / error, never throws);parseSlopReport(data: unknown): ParseResult<ISlopReport>— handwritten type predicate guards on all required fields,statusenum membership,ldr.ldr_scorenumeric,pattern_issues[i]shapeanalyzer.ts:runSlopDetector()return type narrowedany → Promise<ISlopReport>;parseSlopReport()applied afterextractJson(); schema mismatch throws with exactfield / expected / gotpath and version-hint message
Pattern accuracy
patterns/python_lint.py:LintEscapePattern.check()now skips lines that fall inside string/docstring literals —# noqa:text in docstrings (e.g.,"""...has '# noqa: F401'...""") was incorrectly flagged as a live lint suppression; fix uses_string_literal_lines()to collect allast.Constant[str]line ranges and exclude them from the regex scan
Code quality (self-scan audit — avg_deficit 13.85 → 9.80)
cli_commands.py L215:except OSError: passindetect_domain()replaced with debug-level log — domain detection is best-effort but the exception should be observablecli_commands.py L380:except Exception: passin_check_calibration_hint()replaced with debug-level log — calibration hint failure is informational, but silent discard masked the exception;# noqa: BLE001retained (broad catch is intentional for never-block semantics)scripts/global_injector.py: Patch 1 (DEFAULT_CONFIG["weights"]rewrite) removed frominject_config_py()— dogfooding-calibrated values belong only inDOMAIN_PROFILES["general"]["capability_vector"], not in the canonical production fallback; the regex was also outdated (3-key pattern, no purity) so it already MISS-ed, but the wrong design intent was preserved in code
Documentation accuracy
docs/LEDA_CALIBRATION.md §2diagram: removedconfig.py L31: DEFAULT_CONFIG["weights"]injection target — injector only writes toDOMAIN_PROFILES["general"]; added clarifying notedocs/LEDA_CALIBRATION.md §3.1GQG formula: addedmax(1e-4, ...)clamp guards (matchingcore.py:484-487) — previously showed barelog(x)which would be−infat zerodocs/LEDA_CALIBRATION.md §4.3Before column: ddc corrected to0.20²with footnote explaining pre-3.7.0 historical value was0.30docs/CLAUDE_CODE_SKILL.md: loop labelscan -> interpret -> patch -> re-scan -> gatecorrected toscan -> diagnose -> patch -> re-scan -> gate -> calibratein 4 locations; Quality Loop section updated to 7 numbered steps with role labelsclaude-skills/slop-detector/SKILL.md(installed copy): same loop correction applied
README balance
Claude Code Skillsection demoted to compact "Claude Code Integration" block (38 lines → 10 lines) — convenience feature was given equal billing with core detection featuresLEDA Enginesection restored as "Empirical Weight Calibration (LEDA)" with Mermaid flywheel diagram; "Breaking the Self-Referential Bias" bullet list merged into single intro paragraph — three redundant restatements collapsed to one cohesive statement;[Calibration]nav link restored
.slopconfig.yaml — domain_overrides expanded for justified structural complexity
god_function: added overrides fordetect_domain(cc=13, domain trigger scanner),_collect_imports(cc=21/depth=7, DDC import resolver),_analyze_regex(118L, Go line dispatcher),_run_self_calibration(118L, CLI calibration orchestrator),_check_calibration_hint(56L, result formatter)nested_complexity: added overrides for same functions plus_collect_all_members,_collect_noqa_importsignore: addedscripts/generate_download_chart.py— legacy chart utility with optionalmatplotlib/numpydeps not in main venv; phantom_import flags are expected
.gitignore: added scripts/injection_report.json — auto-generated audit trail from global_injector.py, not source
Claude Code Skill — workflow upgrade
claude-skills/slop-detector/SKILL.md: 3-Phase Pipeline execution model added- Phase 1 Triage: structured table (file / score / status / top issue) with session baseline stored for delta comparison
- Phase 2 Deep-Dive: Confidence Routing by status band — CRITICAL_DEFICIT immediate; SUSPICIOUS routes through
/slop-filesecond-pass before escalation (reduces false escalation of borderline files) - Phase 3 Action Plan: ordered fixes with explicit gate-readiness assessment
/slop-deltanew command: before/after comparison table against session baseline; regression detection; "never say fixed without a measured delta" rule enforced- Each command ends with explicit
→ Next:guidance — eliminates user uncertainty about next step lint_escapeadded to Patch Guidance table
VS Code Extension v3.7.1 (vscode-extension/)
- P1: 855-line monolith split into 8 focused modules (
state/analyzer/diagnostics/statusbar/commands/calibration/codeActions/treeview/codelens) - P2:
SlopCodeActionProvider— QuickFix forphantom_import/god_function/lint_escape; "Add to .slopconfig.yaml ignore" action - P3: TreeView sidebar — 3-level hierarchy (file → 4D metric row → issue list); CRITICAL→LOW sort; click-to-navigate; Refresh + Analyze Workspace title-bar buttons
- P4:
SlopCodeLensProvider— file-level summary at line 0 + per-function issue hints;slopDetector.enableCodeLenssetting
Real-world Dogfooding Model
scripts/retrain_model.py: newThresholdClassifier(pure-Python, nosklearnrequired) trained on real dogfooding data- Handled 784 actual samples from 7 distinct repositories with 55.1% bad class distribution
- Achieved stable evaluation:
accuracy=0.7962,precision=0.9524,recall=0.6742replacing previous initial baseline models (accuracy=1.0) - Extracted and applied key thresholds for
ldr_score,inflation_score,ddc_score,god_function_count - Completely replaced
models/training_data.jsonandmodels/slop_classifier.pklwith live representations - Removed legacy
_realsuffixed files to streamline models structure
SKILL.md — CLI surface documented
--emit-leda-yaml/--leda-output/--leda-profile(choices: internal | restricted | public)--cross-filecross-file dependency + clone analysis--governanceCR-EP session artifact emission--gate(SNP) vs--ci-mode hard(CIGate) gate path distinction- ML score availability: appears in
--jsonoutput when ML model is loaded domain_overridescorrected to per-function pattern exemption format
SKILL.md — 10 OSOT violations repaired (Sentinel-verified)
Critical (command contract errors):
- G1:
ddcdefault weight0.30->0.20(matchescore.py:479) - G2:
/slop-gatesplit ----gate(SNP/sr9/di2/jsd/ove, PASS/HALT) vs--ci-mode hard --ci-report(CIGate, exit code) - G3:
DEPENDENCY_NOISEstatus added with exact trigger (DDC < 20% AND no critical patterns AND inflation <= 1.0) - D1: Project-level
CRITICAL_DEFICITthreshold corrected toweighted_deficit_score >= 50; file vs project scope distinguished - D2: CI hard gate completed -- 4 conditions: deficit >= 70, patterns >= 3, inflation >= 1.5, ddc < 0.5
Medium (documentation drift):
- G4:
fhval sparmarked as external Flamehaven tool with install prerequisite - D3: Domain profile names corrected (
web/api,library/sdk,cli/tool,scientific/ml,scientific/numerical,bio,finance) - D4:
domain_overridesYAML corrected -- per-function pattern exemption, not metric threshold override - D5: Self-calibration two-gate structure documented -- outer trigger: 10 multi-run files milestone (
CALIBRATION_MILESTONE=10); inner floor: >= 5 improvements + >= 5 fp_candidates per class. Previous docs described only one gate, causing confusion - D6: DDC warning threshold added (< 0.70 = WARNING, < 0.50 = CRITICAL); LEDA profile
internaldocumented; DDC three-band zone table added
Code bugs (Sentinel post-calibration audit)
Critical:
- BUG-1:
config.py:31DEFAULT_CONFIG weights corrected to{ldr:0.40, inflation:0.30, ddc:0.20, purity:0.10}— calibration had accidentally written general domaincapability_vectorvalues intoweightskey, causing no-init path to useddc=0.6215instead of0.20;puritywas absent (always fell back to GQG hardcoded 0.10) - BUG-1:
config.py:150get_weights()fallback aligned to same values +purityadded (was dead code but divergent) - BUG-2:
cli_renderer.py:500Markdown findings filter threshold corrected0.3->30.0— was comparing 0-100 scale deficit_score to 0.3, causing all files to appear in Detailed Findings section regardless of CLEAN status
High:
- BUG-3:
cli_renderer.py:446,450Test function counts replaced with AST-actual counts via_count_test_functions_ast()— hardcoded+= 5/+= 10per file caused fabricated "Test Evidence" statistics in Markdown/text reports
Medium:
- BUG-5:
self_calibrator.py:697_rewrite_key()scoped toweights:YAML block only — global MULTILINE regex could corrupt identically-named keys in other YAML sections (e.g., comments or custom domain stanzas)
cli_renderer.py split (730 lines → 4 renderer modules)
renderer_rich.py(~270 lines): Rich console rendering,RICH_AVAILABLE,list_patterns,print_rich_report, all_build_*panel helpersrenderer_markdown.py(~240 lines):get_mitigation, test-evidence helpers,_md_*section builders,generate_markdown_reportrenderer_text.py(~80 lines):_text_*helpers,generate_text_reportrenderer_html.py(~30 lines):generate_html_reportcli_renderer.pyconverted to 17-line re-export shim — all existingcli.pyimports unchanged
patterns/python_advanced.py split (1150 lines → 5 domain modules)
python_complexity.py(327 lines):GodFunctionPattern,DeadCodePattern,DeepNestingPattern,NestedComplexityPatternpython_lint.py(102 lines):LintEscapePatternpython_imports.py(282 lines):PhantomImportPattern+ 8 resolution helperspython_clones.py(76 lines):FunctionClonePatternpython_naming.py(123 lines):PlaceholderVariableNamingPattern
Claude Code Skill — claude-skills/slop-detector/
SKILL.mdwith YAML frontmatter (name: slop-detector, description 456 chars)- Four slash commands:
/slop(full project scan + interpretation),/slop-file [path](single file + per-pattern fix guidance),/slop-gate(CI hard gate PASS/FAIL),/slop-spar(adversarial validation viafhval spar) - Implements full
scan -> patch -> re-scan -> gatequality loop with delta reporting - Session-persistent review criteria: quality policy lives in skill layer, not prompt
docs/CLAUDE_CODE_SKILL.md— full skill documentation with command reference, metric explanation table, patch reference, and calibration guide- README
Claude Code Skillsection with install instructions and loop diagram
Documentation accuracy
What It Detectstable: corrected "Three metric axes" to "Four metric axes"; added Purity row (exp(-0.5 x n_critical_patterns)) — consistent with 4D scoring model stated in introduction anddocs/MATH_MODELS.md- Scoring Model: added normalization note — weights sum to 1.10; GQG divides by
total_wso exact normalization is not required (matchesdocs/MATH_MODELS.md:160) - Quick Start: added missing
pip install "ai-slop-detector[go]"extra (was listed in Key Features andpyproject.tomlbut absent from Quick Start) - Positioning: added
Not a style linter. A structural-risk scanner for AI-assisted code.under the tagline
tests/manual_test/audit_report.md,audit_report_full.md,report.md— stale artifacts from previous manual runs; no automated test dependency
Phase 3a — Domain-Aware --init (v3.5.0)
DOMAIN_PROFILESdict inconfig.py: 8 built-in profiles (general,web_frontend,data_science,cli_tool,library,ml_research,backend_api,scientific) each with normalizedcapability_vectorweights (w_ldr,w_inf,w_ddc,w_pur)detect_domain(project_path): heuristic auto-detection from file patterns and directory structure; returns the closest matching domain key- Domain-aware
_run_init(): generates.slopconfig.yamlpre-seeded with the detected domain's weight profile; printed as a user-visible suggestion in CLI output --domainCLI flag: explicitly override auto-detection (slop-detector --init --domain web_frontend)- 21 new tests in
tests/test_domain_init.pycovering all 8 profiles and CLI flag
Phase 3b — JS/TS Analysis via JSAnalyzer v2.8.0
languages/__init__.py: activatedJSAnalyzerfor.js,.jsx,.ts,.tsxextensions (was commented-out stub);LANGUAGE_ANALYZERSdict now maps all four extensionsmodels.py: addedjs_file_results: List[Any]field toProjectAnalysisdataclass;to_dict()serializes each entry via.to_dict()when availablecore.py:_JS_EXTENSIONSfrozenset;_get_js_analyzer()lazy-loader;_analyze_js_files()private method scanning withrglob;analyze_js_file()public API; JS analysis is computed before the Python early-return path so pure-JS projects return correct resultsanalyze_project()early-return path now includesjs_file_resultsin the returnedProjectAnalysis(previously JS results were lost when no Python files were found)optional dep [js]:tree-sitter>=0.25.0,tree-sitter-javascript>=0.23.0,tree-sitter-typescript>=0.23.0(regex fallback active when not installed)- 32 new tests in
tests/test_js_analyzer.py: instantiation, line counting, slop scoring, issue detection (regex fallback), TS-specificanydetection, AST mode (skipped without tree-sitter), andSlopDetectorintegration
Phase 3c — Go Analysis via GoAnalyzer v1.0.0
languages/go_analyzer.py: standaloneGoAnalyzerclass withGoIssue+GoFileAnalysisdataclasses; detectsgo_empty_func,go_panic,go_fmt_print,go_ignored_error,go_todo_comment,go_god_function; regex fallback always active; optionaltree-sitter-goguard for future AST enrichmentlanguages/__init__.py: importsGoAnalyzer;.goadded toLANGUAGE_ANALYZERSmodels.py:go_file_results: List[Any]field added toProjectAnalysis;to_dict()serializes via.to_dict()per entrycore.py:_GO_EXTENSIONSfrozenset;_get_go_analyzer()lazy-loader;_analyze_go_files()private method;analyze_go_file()public API; Go analysis hoisted before early-return (same pattern as JS — pure-Go projects populatego_file_resultscorrectly)optional dep [go]:tree-sitter>=0.25.0,tree-sitter-go>=0.23.0- 24 new tests in
tests/test_go_analyzer.pycovering all patterns, slop scoring, andSlopDetectorintegration
- New
test-jsjob: installs.[dev,js]and runstests/test_js_analyzer.pyon Python 3.11 - New
test-gojob: installs.[dev,go]and runstests/test_go_analyzer.pyon Python 3.11
- Schema v5
project_id(history.py):project_id TEXTcolumn added (auto-migrated). Set tosha256[:12]of the resolved cwd at scan time. Prevents cross-project signal pollution in the global~/.slop-detector/history.db. - Project-scoped calibration (
self_calibrator.py,cli_commands.py):calibrate()acceptsproject_idand passes it to_load_history()and_extract_events()._record_history()and_check_calibration_hint()now compute and threadproject_idvia new_compute_project_id()helper. - Better calibration trigger (
cli_commands.py,history.py): milestone is nowcount_files_with_multiple_runs(project_id)instead ofcount_total_records(). A first-time scan of N files records N rows but zero repeat-file pairs, sototal_records % 10 == 0was a false trigger. Only files scanned ≥2× can produce improvement/fp_candidate events. - Domain-anchored grid search (
self_calibrator.py):_grid_search()acceptsdomain_anchordict; when provided each dimension's range is constrained to[anchor - DOMAIN_TOLERANCE(0.15), anchor + DOMAIN_TOLERANCE](clipped to absolute MIN_W/MAX_W)._check_calibration_hint()passescurrent_weightsas the anchor so calibration stays within the domain's meaningful weight region. DOMAIN_TOLERANCE = 0.15constant added toself_calibrator.py.- Domain-drift warning (
self_calibrator.py):CalibrationResultgainswarnings: List[str]field (empty by default). After a successful calibration,calibrate()compares each optimal dimension weight againstdomain_anchor(orcurrent_weightsas fallback); any dimension that drifts more thanDOMAIN_DRIFT_LIMIT = 0.25appends a human-readable warning. Warnings are surfaced by_run_self_calibration()with a yellow[!]prefix (rich) or plain[!]prefix (plain output). DOMAIN_DRIFT_LIMIT = 0.25constant added toself_calibrator.py.- 16 unit tests in
tests/test_calibration_patches.py: P2 (6 tests: empty DB, single-run exclusion, multi-run count, 3-run dedup, project_id scoping, cross-contamination guard), P1 (3: project_id persisted, null stored as null,_load_historyfilter), P3 (3: unconstrained covers full ldr range, constrained stays within ±DOMAIN_TOLERANCE, fewer candidates), P4 (4: field exists + defaults empty, independent instances, drift warning fires, no warning when drift small). 308/308 green.
jqparse error in "Self SLOP Detection" CI job (cli_commands.py): root cause was_check_calibration_hint()printing calibration milestone text to stdout after the JSON block whensrc/contained ≥10 files (a CALIBRATION_MILESTONE=10 multiple). jq received{...json...}\n[*] Calibration milestone...and rejected it as invalid JSON. All_check_calibration_hint()prints now go tofile=sys.stderr.float("inf")in JSON output (metrics/inflation.pyL157):_compute_inflation_score()returnedfloat("inf")whenlogic_lines == 0andeffective_jargon > 0. Python'sjson.dumpsserialises this asInfinity(invalid RFC 8259). Changed to10.0(same cap as the normal code-pathmin(..., 10.0)) — maximally-inflated sentinel, no JSON leakage.avg_inflationfilter regression (core.py): previous fix usedstatus != "error"as an inf guard; with the sentinel changed to999.0the guard became dead code. Replaced withmath.isfinite(r.inflation.inflation_score)— correctly excludes any non-finite value regardless of status string._sanitize_for_jsonhardened (cli.py): addedtuplehandling alongsidelist; addedjson.dumps(..., allow_nan=False)so any residual non-finite float raisesValueErrorimmediately rather than silently emitting invalid JSON.- E2E calibration tests (
tests/e2e_v321/test_e2e_v321.py):milestone_firedandauto_calibratedassertions now check both stdout and stderr so the tests remain green after the print redirection.
FileRole.STUB(file_role.py): new role for pure Protocol/ABC interface stubs. Files where all top-level class definitions inherit fromProtocol,ABC, orABCMetaand contain no top-level function definitions are now classified as STUB. STUB skipsldrandpatternschecks —...-body stubs and clone patterns are structurally expected, not quality deficits.- STUB regression test (
tests/test_fp_reduction.py⑥): asserts Protocol-stub files produceFileRole.STUBandSlopStatus.CLEANto prevent silent regression. - Auto-detect
.slopconfig.yaml(cli.py): when--configis not specified the CLI now probes the project root (project mode) or the file's parent directory (single-file mode) for.slopconfig.yamland loads it automatically.
classify_file()signature:tree: ast.AST→tree: ast.Module;ast.ASThas no.bodyattribute —ast.parse()always returnsast.Module. Fixes mypyattr-definederror.- Python 3.8 CI compatibility: replaced
with (A, B):parenthesized context manager syntax (Python 3.9+) with nestedwithstatements intest_leda_injection.pyandtest_cli.py::test_main_emit_leda_yaml.
LEDA injection emission for SPAR-adjacent review
- Added
slop_detector/leda_injection.pyto emit a structured YAML surface for downstream SPAR review. - Added CLI flags:
--emit-leda-yaml--leda-output
- The emitted payload carries:
- project identity
- live analysis summary
- calibration surface
- claim-risk candidates
- suggested maturity hints
- SPAR review hints
- Added tests covering payload generation and CLI emission.
- Added LEDA redaction profiles:
internalrestrictedpublic
- Default CLI emission now uses
restrictedto reduce accidental exposure of implementation weakness surfaces in exported YAML.
Per-Rule FP Rate Tracking (LEDA v3.4.0 — Phase 2A)
history.pyschema v4: newfired_rules TEXT DEFAULT NULLcolumn stores{"pattern_id": count}JSON per scan row; old rows degrade gracefully toNULLHistoryEntry.fired_rules: Optional[str]field +record()builds the JSON dict fromfile_analysis.pattern_issuesSelfCalibrator._calc_per_rule_fp_rates(): computes per-rule FP rate across all labeled CalibrationEvents; only rules seen ≥MIN_RULE_OCCURRENCES=3times included_parse_fired_rules(json_str) -> List[str]: module-level helper for safe JSON parsingCalibrationEvent.rule_ids: List[str]: pattern IDs fired during that eventCalibrationResult.per_rule_fp_rates: Dict[str, float]: rule_id → FP rate output- Rich per-rule FP table in
--self-calibrateoutput (rules ≥50% shown; ≥70% = HIGH FP) - Plain-text fallback for non-rich environments
Purity Weight Ceiling (LEDA v3.4.0 — Phase 2B)
MAX_PURITY_WEIGHT = 0.25constant: caps purity dimension at 25% of weight budget (was implicitly up to 65% via MAX_W; purity is count-based and more volatile than ratios)MIN_RULE_OCCURRENCES = 3constant: minimum events per rule to include in FP rate stats- Grid search
_grid_search()respects ceiling: purity iterates[0.10, 0.15, 0.20, 0.25]only
File Role Classifier (file_role.py)
- New
FileRoleenum:SOURCE,INIT,RE_EXPORT,TEST,MODEL,CORPUS classify_file()auto-detects the role of each file being analyzedROLE_SKIPmap: per-role metric suppression (e.g., INIT skipsldr+ddc)_SkipProxyincore.py: thin proxy that nullifies skipped metric contributions without duplicating the GQG scoring formula
DDC Annotation-Only Import Tracking (FP ①)
UsageCollectornow tracksannotation_used— names referenced only in type annotations- Imports used exclusively in type hints (e.g.,
argparse.Namespace) are excluded from bothunusedlist andusage_ratiodenominator - Eliminates false-positive SUSPICIOUS on files with annotation-heavy APIs
# noqa: F401 Recognition (FP ②)
_collect_noqa_imports()scans inline comments for# noqa: F401markers- Such imports are excluded from
unusedand denominator — treated as intentional suppressions
__all__ Re-Export Recognition (FP ③)
_collect_all_members()collects names published via__all__- Imports re-exported through
__all__are excluded fromunused— they have runtime value
analyze_file()andanalyze_code_string()incore.pynow accept askipset derived from file role classification_calculate_slop_status()and_build_metric_warnings()acceptskipparameterDEPENDENCY_NOISEoverride respectsskip— won't fire for INIT/RE_EXPORT files
usage_ratiocalculation now correctly usesruntime_imports(all imports minus excluded set) as denominator, not raw total imports
P1 — Auto-calibration at milestone (cli.py _check_calibration_hint())
- At every
CALIBRATION_MILESTONE(10) scans, calibration now runs automatically and applies to.slopconfig.yaml(if it exists and calibration is confident). - Prints per-weight diff:
ldr: 0.40 -> 0.45etc. for full transparency. - Only applies when
result.status == "ok"—CONFIDENCE_GAPandno_changesafety gates prevent noisy or regressive updates. - This closes the "The more you use it, the smarter it becomes" loop end-to-end;
no manual
--self-calibrate/--apply-calibrationrequired.
P2 — Git commit context as noise filter (history.py + cli.py + self_calibrator.py)
_get_git_context()incli.py: capturesgit rev-parse --short HEADandgit branch --show-currentonce per run (3 s timeout, gracefulNonefallback).history.py record()acceptsgit_commitandgit_branchkwargs and stores them.self_calibrator.py _load_history()now SELECTsgit_commitand includes it in the returned dict._classify_run_pair()uses git context as a noise signal:- improvement filter: same commit + score drop → measurement noise, skip.
- FP candidate filter: different commits + stable hash → ambiguous signal, skip.
- When
git_commitisNULL(non-git projects), original heuristic applies unchanged.
- Result: fewer but higher-fidelity labeled events → more reliable calibration signal.
P3 — Per-class minimum thresholds (self_calibrator.py)
MIN_EVENTS = 20replaced byMIN_IMPROVEMENTS = 5/MIN_FP_CANDIDATES = 5.CALIBRATION_MILESTONE = MIN_IMPROVEMENTS + MIN_FP_CANDIDATES(= 10).calibrate()checks each class independently: both must meet their floor before grid search runs. Prevents class-imbalanced calibration.- 4D model's continuous
tiebreaksignal makes 5+5 statistically sufficient (where 3D binary rates required 10+10). --min-historyCLI arg: default changed from 20 → 5 (per-class floor).cli.pyimport updated:MIN_EVENTS→CALIBRATION_MILESTONE.
self_calibrator.py calibrate(): defaultmin_eventschanged fromCALIBRATION_MILESTONE(10) toMIN_IMPROVEMENTS(5); old default causedmax(10, MIN_IMPROVEMENTS=5) = 10per-class floor, defeating the 5+5 design intent. Now correctly yieldsmax(5, 5) = 5per class.cli.py _run_self_calibration():getattr(args, "min_history", 20)default corrected to 5.
ml/self_calibrator.py — F1: 4D calibration (purity dimension)
CalibrationEventandWeightCandidatenow carry apurityweight dimension._recompute_deficit()computespurity_score = exp(-0.5 * n_critical_patterns): 1.0 when no critical patterns, decays toward 0 as critical patterns accumulate._grid_search()extended from 3D to 4D simplex: three nested loops (i, j, p), k = GRID_STEP − i − j − p; constraints keep each weight in [MIN_W, MAX_W].apply_to_config()now writes all four keys:ldr,inflation,ddc,purity.CalibrationResult.optimal_weightsnow includes a"purity"key.- Backward compatible: old
history.dbrows defaultn_critical_patterns = 0→purity_score = 1.0→ no change to deficit from old records.
ml/self_calibrator.py — internal refactor: event extraction decomposed
_extract_events()split into three focused helpers:_group_runs_by_file(rows)— groups + sorts rows by file and timestamp_classify_consecutive_runs(file_path, runs, seen_fp_files)— per-file loop_classify_run_pair(file_path, r_now, r_next, drop, seen_fp_files)— single pair
- Reduces nesting depth (depth=4 → depth=3), CC (11 → 3 per function), and lines per function (54 → 10 each). No behaviour change.
history.py — F1 schema: n_critical_patterns column
_SCHEMA_V2includesn_critical_patterns INTEGER NOT NULL DEFAULT 0._migrate()adds the column when upgrading from schema v1.HistoryEntrydataclass gainsn_critical_patterns: int = 0.record()computes the count frompattern_issues(CRITICAL severity only)._insert()writes the value in the 12-column INSERT.count_total_records() -> intmethod added for auto-trigger hint.
cli.py + config.py — F2: --init bootstrap
slop-detector --init [path]generates a fully documented.slopconfig.yamlin the target project root (or.by default).- Project type auto-detected (python / javascript / go) from
package.json/go.mod. .gitignoreentry injected automatically with an explanatory security comment.--force-initflag overwrites an existing.slopconfig.yaml.generate_slopconfig_template(project_type)added toconfig.py.
cli.py — F3: auto-trigger calibration hint
- After every run that records history,
_check_calibration_hint()fires when total records cross a MIN_EVENTS milestone (every 20 records). - Output:
[*] Calibration available (N events). Run --self-calibrate to optimize weights. - Closes the LEDA loop:
--init→ scan (auto-log) → hint →--self-calibrate→--apply-calibration.
README.md — F4: Security Considerations section
- Documents what
.slopconfig.yamlcontains (domain overrides = codebase weakness map) and why it should default to.gitignorefor private projects. - Documents
history.dblocation (~/.slop-detector/) and its safety properties. - Navigation bar updated; scoring section reflects all 4 calibrated dimensions.
.slopconfig.yaml — purity weight added + ML calibrator overrides
weights:block now includespurity: 0.10(4D calibration, v3.2.0+).nested_complexity.domain_overridesadds_grid_search(depth=6, cc=10): 4D grid search requires n-1 nested loops by mathematical necessity.god_function.domain_overridesaddscalibrate(lines=100) andapply_to_config(lines=70): orchestrator and YAML comment-preserving updater patterns are inherently multi-step.- Self-scan result: 44/44 files CLEAN (was 42/43 before this patch).
cli.py — P6: --min-history default / fallback drift (doc drift)
--min-historyargparser default was hardcoded10; fallback in_run_self_calibrationalso used10. Both now sync toMIN_EVENTS = 20fromself_calibrator.py.- Impact: without this fix,
slop-detector --self-calibrate(no--min-historyflag) would trigger calibration with only 10 events — contradicting the documented threshold and reducing statistical reliability of the result. - Fix:
default=20inadd_argument,getattr(args, "min_history", 20)in runner.
ml/self_calibrator.py — P1: apply_to_config comment preservation
- Replaced
yaml.safe_load+yaml.dumpfull-file rewrite with a targeted regex in-place approach: only the numeric values on theldr:,inflation:,ddc:lines are rewritten. All comments,domain_overrides,ignorepatterns, and every other key are left untouched. - Handles three edge cases: all keys present (common), some keys missing (insert
under existing
weights:block), noweights:block (append one). - Eliminates the risk of losing annotated
.slopconfig.yamlgovernance docs on--apply-calibration.
ml/self_calibrator.py — P2: FP candidate deduplication
_extract_events()previously emitted onefp_candidateper consecutive run pair per file. A file unchanged across 50 runs generated 49 fp_candidates, heavily biasing the FP pool and causing the calibrator to recommend inflatedw_ddcvalues.- Fix: introduced
seen_fp_filesset — each file now contributes at most onefp_candidateevent regardless of how many stable consecutive runs it has.
ml/self_calibrator.py — P4: MIN_EVENTS raised from 10 → 20
- At 10 events, a binary fp_rate on 3 FP candidates has only 4 possible values (0.0 / 0.33 / 0.67 / 1.0), making grid-search rankings statistically unreliable.
- Raised to 20 events for minimum viable calibration signal.
README.md — P3: weight drift correction
- Scoring Model section showed
ddc=0.20; actual default inconfig.pyand.slopconfig.yamlisddc=0.30. Corrected. - Added explicit note that
purity=0.10is a fixed coefficient, not calibrated.
.gitignore — P5: slop-detector runtime artifact exclusion
- Added
.slop-detector/to cover any local cache directories created by workflow variants. Documents that.slopconfig.yamlis intentionally committed in this project (open-source governance transparency) while explaining that private projects should exclude it via--init(coming in v3.2.0).
ml/data_collector.py — structural refactor + debug output
- Extracted two inner counting loops in
from_analysis()as static helpers:_count_severities(issues)and_count_cross_lang(issues). Reducesfrom_analysisfrom 75 lines / depth=7 to ~30 lines / depth=3. print(f"[!] Failed ...")error handlers replaced withlogger.warning(...). Module-levellogger = logging.getLogger(__name__)added.save_dataset()progress prints marked# noqa: T201(intentional CLI output).
.slopconfig.yaml — domain overrides gap fill
- Added
nested_complexityoverrides for functions not previously covered:_analyze_function,_detect_unused_imports,_count_implementation_lines,_count_module_implementation_lines,analyze. - Added
god_functionoverrides for the same functions, plus ML pipeline:run,run_on_real_data,_train_from_samples,_build_dataset,_extract_features. - Removed duplicate
god_functionblock introduced by incremental editing. - Self-scan result: 43/43 files CLEAN (was 4 suspicious before this patch).
Clone Detection visibility
function_clone_clusterresults were only visible in the Issues section; Core Metrics table showed no duplication signal (reported via community issue).- Fix: added "Clone Detection:" row to the Core Metrics table.
CRITICAL/HIGH severity shown when
function_clone_clusterfires;PASSotherwise. No model changes — reads from existingpattern_issueslist.
Table style unification (CLI UX)
- Project-level output mixed three Rich table box styles
(
SIMPLE,MINIMAL_DOUBLE_HEAD,ROUNDED). All tables now usebox.ROUNDEDwithheader_style="bold cyan". - Jargon entries in File Analysis Notes column trimmed to first 3 terms
- "+N more" — prevents column overflow on heavily-flagged files.
- File Analysis Status severity color extended to
critical_deficitvariant.
VS Code extension (v3.1.1)
extractJson(): strips[INFO]log lines beforeJSON.parse— prevents parse failures when CLI emits log output alongside JSON.recordHistorysetting now correctly passes--no-historyto the CLI.- Summary diagnostic message includes Clone Detection signal from
pattern_issues. - Status bar tooltip uses null-safe metric access and shows Clone PASS/CRITICAL.
- Workspace analysis: replaced single-line notification with a QuickPick list of deficit files sorted by score; clicking a file opens it in the editor.
- History Trends: formatted column table (Runs/Latest/Best/Worst/Trend) replaces raw JSON dump in Output panel.
uv tooling
- Added
.python-versionanduv.lockto.gitignore.
Pattern refactoring (self-inspection driven)
placeholder.py: extracted_strip_docstring,_has_abstractmethod,_empty_container_repr,_is_placeholder_stmtas module-level helpers. Allcheck_nodemethods now delegate to helpers (8–15 lines each vs. 20–70). Self-scan deficit score: 70.3 → 43.7.python_advanced.py: added_make_god_issue()toGodFunctionPattern; added_collect_numbered_vars()to reduce nesting depth inPlaceholderVariableNamingPattern. Self-scan deficit score: 74.0 → 66.7.- No behavior changes; all 188 tests pass.
ml/self_calibrator.py — _recompute_deficit: aligned to geometric mean
- The calibrator's objective function now mirrors GQG exactly. First-generation calibrator used a weighted arithmetic mean; the scorer uses a weighted geometric mean. AM ≥ GM always — on files with uneven dimension profiles, this produced a ~5-7pt gap between what the calibrator optimized for and what the scorer computed. Weights were tuned against a simpler approximation of the target formula.
- Refinement: replaced
ldr*w + (1-inf)*w + ddc*wwithexp(Σw_i*ln(v_i)/Σw_i). Purity excluded from calibrator (it depends on pattern count, not weights).
metrics/inflation.py — complexity modifier baseline: cc=3 → cc=1
- Previous formula:
max(1.0, 1.0 + (cc - 3.0) / 10.0)produced modifier=1.0 for cc=1,2,3 — the three most common complexity levels paid no complexity premium on jargon inflation. Minimum meaningful baseline is cc=1. - Refinement:
max(1.0, 1.0 + (cc - 1.0) / 10.0). cc=2 now gets modifier=1.10.
core.py — purity weight now configurable
w_pur = 0.10was hardcoded, invisible to the calibrator and not honored by.slopconfig.yamlweights.purityfield despite being documented.- Refinement:
w_pur = weights.get("purity", 0.10). Default unchanged; the config surface now matches the implementation.
return_constant_stub (extended) — empty container stubs
return {},return [],return (),return set()now triggerreturn_constant_stubalongside existingreturn True/False/"string"/0detection.- Same applies to
interface_only_classplaceholder check.
function_clone_cluster (new) — DI2-based AST clone detection
- Detects files where a large cluster of functions have near-identical AST node-type distributions (pairwise JSD < 0.05).
- Addresses the
complexity_hidden_in_helpersadversarial evasion pattern: a god function split into N structurally identical one-liners evades all per-function gates (god_function, nested_complexity) but produces a measurable file-level signal. - Thresholds: ≥ 6 clones → CRITICAL; ≥ 4 clones → HIGH.
- Algorithm: 30-dim AST histogram per function → pairwise JSD →
BFS connected components. Ported and adapted from
Protocol-ReGenesis-Engine
src/core/math_models.py(itself a Python port of Flamehaven-TOE v4.5.0toe/math/di2.py). - New module:
metrics/stub_density.py—_jsd(),_node_histogram(),_find_largest_clone_group(),calculate_stub_density().
placeholder_variable_naming (new, v1.0) — naming pattern detection
- Two sub-checks:
- High single-letter parameter count: ≥ 5 single-letter params (excluding
self,cls,_) → HIGH. E.g.def process(a, b, c, d, e, f, g). - Sequential numbered variable pattern: ≥ 8 in sequence → HIGH;
≥ 4 → MEDIUM. E.g.
r1, r2, r3 ... r12.
- High single-letter parameter count: ≥ 5 single-letter params (excluding
- Addresses
vocab_clean_meaninglessadversarial evasion: meaningful-vocabulary code with zero semantic content evades all existing pattern gates, but placeholder naming is structurally detectable. - v1.0 design note: detects naming style, not semantic quality. Known false
positive zone: math/science libraries using single-letter variable conventions.
Configure with
domain_overridesor--config ignoreto suppress.
New spar subcommand in fhval (flamehaven-validator) providing a
3-layer adversarial regression loop for the scoring model:
- Layer A (ground truth anchors): 5 known code patterns with expected
deficit ranges. Any deviation = scoring model regression.
clean_trivial: deficit ≤ 15 (regression guard)extreme_jargon: deficit ≥ 40 (regression guard)stub_class_8_methods: deficit ≥ 30 (was ANOMALY in v3.0.x)fragmented_god_function: deficit ≥ 10 (was ANOMALY in v3.0.x)vocab_clean_meaningless: deficit ≥ 8 (was ANOMALY in v3.0.x)
- Layer B (peer challenges): 4 documented architectural limitations with severity classification.
- Layer C (existence probes): 4 probes testing whether each metric measures what it claims (LDR genuineness, inflation blindspot, DDC annotation gap, calibrator consistency).
SPAR score progression: 55 → 85 PASS after v3.1.0 refinements.
patterns/__init__.py: registeredFunctionClonePattern,PlaceholderVariableNamingPattern.
- All 188 tests pass. No public API changes.
vocab_clean_meaninglessSPAR check remains CONSISTENT via naming pattern detection (v1.0). The deeper semantic gap (arithmetic with no meaning) is documented in SPAR Layer C as a known scope limitation of static analysis.
Self-scan before: avg_deficit=23.57, 15 deficit files, status=suspicious Self-scan after: avg_deficit=20.33, 12 deficit files, status=clean
analysis/cross_file.py — deficit 70.3 → 28.7 (critical_deficit → clean)
- Extracted
_hash_function_body(func_node)from_extract_functions— removes 4-deep nesting - Rewrote
_extract_importsusing early-continue; removed single-valuefor ext in (".py",)loop - Promoted nested
dfs()closure to_dfs(self, ...)private method (was triggering nested_complexity as a closure inside_detect_cycles) - Extracted
_build_exact_duplicate_pairs(hash_index)from_detect_duplicates— separates hash indexing from pair enumeration
ci_gate.py — deficit 69.3 → 22.3 (inflated_signal → clean)
- Extracted
_classify_files(result)— removes file-classification loop from_evaluate_project - Added
_verdict_soft/hard/quarantine()helpers — replaces 87-line if/elif/else mode dispatch with a dict-dispatch pattern; reduces_evaluate_projectto ~20 lines - Extracted
_evaluate_file_quarantine(result, verdict)— removes nested QUARANTINE branch from_evaluate_file - Extracted
_has_uncovered_production_claims(ctx_jargon)— flattens the 4-deep loop in_check_claims_evidence - Replaced
for file_result in result.file_results: if ...: breakwithnext()in_update_quarantine - Moved production-claim strings to
_PRODUCTION_CLAIMSclass constant (was re-declared inline)
cli.py — deficit 68.4 → 20.9 (inflated_signal → clean)
- Extracted
_categorize_pattern(pattern) → str— removes 4-branch if/elif fromlist_patterns - Extracted
_print_pattern_category(category, patterns)— removes triple-nested print loop - Extracted
_file_has_production_claims(f_res)— removes 4-deep evidence-detail loop from_collect_test_evidence_stats; moved shared production-claim set to_PRODUCTION_CLAIMS_CLImodule constant - Extracted
_write_json_output(args, result)— removesif args.output:nesting insideif args.json: - Extracted
_route_file_output(out, result, rich_ok)— separates format routing from_handle_outputdispatcher - Extracted
_run_analysis_phase(args, detector)— removes innerif args.project:branch frommain's try block - Extracted
_text_file_lines(fr)— removes 4-deep jargon-detail loop from_text_project_section; converts inner for-with-if to list comprehension
.slopconfig.yaml — Rule-0 false-positive prevention
- Added explicit
# RULE-0 NOTEblock documenting thattests/corpus/and__init__.pyare intentional slop fixtures and packaging boilerplate respectively - Documents correct invocation:
--config .slopconfig.yamlis required when running SIDRCE or slop-detector from project root
All 188 tests pass. No public API changes.
Project package auto-discovery (_find_project_root, _discover_project_packages)
- Walks up to 12 directory levels to locate
pyproject.toml,setup.py,setup.cfg, or.git. - Scans the found root for internal project packages:
src/layout, flat layout, and[tool.setuptools.packages.find] wheredirective. - Parses
[project.dependencies]and[project.optional-dependencies]to extract declared package names, stripping vendor prefixes (e.g.flamehaven_nnsl→nnsl). - Results cached per-process (
_PROJECT_PACKAGES_CACHE) — zero repeated I/O within a run.
Import guard detection (_collect_import_guard_lines, _IMPORT_GUARD_EXC_NAMES)
- AST walk of every
ast.Trynode in the file; collects line numbers ofimport/fromstatements insidetrybodies whoseexcepthandlers catch any of:ImportError,ModuleNotFoundError,Exception,BaseException. - Prevents false positives on broad-guard patterns (
except Exception:) used in API adapter modules and framework bridges.
3-tier classification (_make_issue)
| Tier | Condition | Severity | Message |
|---|---|---|---|
| Internal | Module is part of current project | (skip) | — |
| Guarded | Import inside try/except ImportError block |
MEDIUM | "Undeclared optional dependency" |
| Hard | Unresolvable, no guard | CRITICAL | "Phantom import" |
Result: eliminates the cascade where 252 project-internal phantom hits drove DDC → 0,
GQG → ln(1e-4), and deficit_score → 100 for every file in a src-layout project.
ldr.calculate()now detects empty (content-free)__init__.pyfiles before computing the ratio. Empty packaging init →ldr_score=1.0,grade="N/A",is_packaging_init=True.- Prevents
total_lines=0→ldr_score=0.0→GQG → ln(1e-4)cascade on standardsrc/<pkg>/__init__.pyfiles. LDRResultmodel: newis_packaging_init: bool = Falsefield, serialized viato_dict().
Previously any function exceeding lines_threshold OR complexity_threshold was flagged HIGH.
This produced false positives on verbose-but-simple domain code: physics constant tables,
routing dispatch blocks, and rule interpreters with low cyclomatic complexity.
New severity routing:
| Condition | Severity |
|---|---|
cc > complexity_threshold (regardless of length) |
HIGH |
lines > lines_threshold AND cc > complexity_threshold |
HIGH |
lines > lines_threshold AND cc <= 5 |
LOW |
NotImplementedPattern — skip @abstractmethod
raise NotImplementedErrorinside an@abstractmethod-decorated method is the correct Python ABC pattern, not a placeholder. Added the same decorator check already present inPassPlaceholderPattern.
EmptyExceptPattern — rewritten as 3-tier
| Handler | Severity | Message |
|---|---|---|
Bare except: pass |
CRITICAL | "Bare 'except: pass' swallows all exceptions including SystemExit" |
except (ImportError|ModuleNotFoundError): pass |
LOW | "optional dependency guard; verify this is intentional" |
except SomeType: pass |
MEDIUM | "silently discards the exception" |
InterfaceOnlyClassPattern — return self/return cls counted as placeholder
- Method-chaining stubs (
return self) provide no meaningful domain value in an otherwise unimplemented class. Now counted toward the placeholder threshold.
- Applied to Flamehaven-TOE v4.5.0 (83 files, src-layout, 11 optional deps):
- Before: 252 CRITICAL phantom imports, deficit_score=100 on all files, status=
critical_deficit - After: 0 CRITICAL phantom imports, 11 MEDIUM (correctly classified optional deps),
deficit_score avg ~18.1, status=
clean
- Before: 252 CRITICAL phantom imports, deficit_score=100 on all files, status=
- 188 tests pass; ruff + mypy clean.
D4 — ReturnConstantStubPattern (return_constant_stub, HIGH)
- New pattern detecting functions whose entire body (excluding docstring) is a single
return <constant>statement (return 42,return True,return "ok", etc.). - Targets the
ldr_gaming/stub_with_real_structureadversarial evasion: dense one-liner stubs score high on LDR but carry zero semantic value. - Excluded: dunder methods (
__len__,__bool__,__hash__, ...) which legitimately return constants;@abstractmethoddecorated functions;return None(already covered byReturnNonePlaceholderPattern). InterfaceOnlyClassPatternupdated to also countreturn <constant>methods as placeholders.
D2 — Configurable god_function thresholds with domain_overrides
GodFunctionPatternnow acceptscomplexity_threshold,lines_threshold, anddomain_overridesconstructor arguments.- Thresholds configurable per-project via
.slopconfig.yaml:patterns: god_function: complexity_threshold: 10 # default lines_threshold: 50 # default domain_overrides: - function_pattern: "evaluate" # fnmatch wildcard supported complexity_threshold: 80 lines_threshold: 300
function_patternusesfnmatch— supportsevaluate,validate_*,check_?, etc. First matching override wins. Falls back to global thresholds if no match.Config.get_god_function_config()added;core.pypasses it toget_all_patterns().- Rationale: clinical governance engines, rule interpreters, and safety systems have inherent domain complexity that is not accidental. A single config entry suppresses false positives without disabling the pattern globally.
get_all_patterns()now accepts optionalgod_function_configdict — no breaking change, default behavior (cc=10, lines=50, no overrides) is identical to v3.0.0.
DCF (Distributional Code Fingerprint)
_compute_dcf(tree)module-level function:P(node_type | file) = count(node_type) / total_nodes. Genuine probability distribution over AST node types; values in [0,1], sum to 1.FileAnalysis.dcf: Dict[str, float]— stores the DCF for each analyzed file.analyze_file()andanalyze_code_string()now compute and attach DCF (reuses already-parsed AST).
GQG (Geometric Quality Gate)
_calculate_slop_statusnow uses weighted geometric mean (GQG) instead of arithmetic mean.- Formula:
Omega = exp(sum(w_i * ln(max(1e-4, v_i))) / sum(w_i)) - AND-gate property: any dimension collapsing to 0 drives Omega to 0; no compensation.
- Dimensions: ldr (w=config), inflation_q (w=config), ddc (w=config), purity (w=0.10 fixed).
- Purity:
exp(-0.5 * n_critical_patterns)— exponential penalty for CRITICAL-severity patterns.
MST H0 VR Structural Coherence
_js_divergence(p, q)— Jensen-Shannon divergence in [0,1] (log-base-e, normalized)._compute_coherence_vr(file_dcfs)— MST H0 persistence coherence over file DCFs.coherence = 1 - max_mst_edgewhere max_mst_edge = longest edge in Prim's MST of pairwise sqrt-JSD distances. Epsilon-free; equivalent to max H0 persistence in the Vietoris-Rips filtration.analyze_project()now collectsfile_dcfsand computes structural coherence when >= 2 files.ProjectAnalysis.structural_coherence: float— 1.0 = all files structurally uniform.ProjectAnalysis.coherence_level: str— "vr_structural" when computed, "none" otherwise.
Gate comment fix
gate/slop_gate.py:_normalize_jsd()now documents that thejsdkey is not information-theoretic JSD. Key name preserved for SNP contract backward compatibility. True DCF-JSD is available viaFileAnalysis.dcf(v3.0+).
_calculate_slop_status: arithmetic mean replaced with GQG (breaking: scoring values change).DEPENDENCY_NOISEoverride now guarded bynot critical_patterns and inflation <= 1.0to prevent mislabeling multi-cause failures as dependency noise under GQG.
- New
src/slop_detector/ml/self_calibrator.py— adaptive weight optimizer. - Labels derived from user behaviour, not formula outputs (breaks tautology):
improvement_event: deficit > 25 in run[i], dropped > 10 in run[i+1] → user fixed itfp_candidate: deficit > 25, same file_hash in next run, no change → user ignored it
- Grid search over weight simplex
{w_ldr + w_inflation + w_ddc = 1.0, wi ∈ [0.10, 0.65]}at 0.05 resolution (no new dependencies — pure stdlib + yaml). - Continuous tiebreaker (LEDA MetaLearning pattern): when candidates tie on binary FN+FP rate,
secondary sort by
avg_fp_deficit − avg_tp_marginbreaks the tie. - Copilot Guardian-style confidence gap: if gap between #1 and #2 < 0.10, reports
insufficient_datarather than applying a weakly-supported calibration. --apply-calibration [CONFIG]: writes optimal weights to.slopconfig.yaml(default) only whenstatus == ok.--min-history N: override minimum event threshold (default: 10).- CLI output: 3-panel Rich layout (status, event counts, weight delta table with ± colors).
First live run on Flamehaven history.db (180 unique files, 62 improvements, 176 FP candidates):
| Current | Optimal | |
|---|---|---|
| ldr | 0.40 | 0.10 |
| inflation | 0.30 | 0.25 |
| ddc | 0.30 | 0.65 |
| combined error | 1.1069 | 0.9985 |
| confidence gap | — | 0.1088 |
Interpretation: high FN rate (91.9%) against metric-only recomputed deficits indicates pattern penalties dominate this codebase's scoring. Weight calibration operates on the metric component only; pattern-driven deficits are orthogonal and unaffected.
_render_rich_single_filewas rendering a singlebox.DOUBLEpanel containing raw key-value text — inconsistent with the documented 3-panel layout described in README and shown in interface screenshots.- Reconnected the intended design:
- Panel 1 (
box.ROUNDED): File path, status badge, deficit score — right-aligned. - Panel 2 (
box.ROUNDED): LDR / ICR / DDC / Justification Ratio / ML Prediction with per-row color coding (red/yellow/green). - Panel 3 (
box.ROUNDED): Review questions with inline severity badges ([CRITICAL]red,[WARNING]yellow,[INFO]blue).
- Panel 1 (
- Header banner unified to
box.ROUNDEDto match panel chrome. - Helpers added:
_build_header_table,_build_metrics_table,_build_questions_panel. - Single-file text-report path (
_build_single_file_content) preserved unchanged.
print_rich_report()split into six focused helpers:_build_rich_summary_tables,_build_rich_files_table,_render_rich_project,_build_single_file_content,_append_pattern_issues_rich,_render_rich_single_file. Each is now ≤ 40 logic lines.main()extracted to_build_arg_parser(),_evaluate_ci_gate(),_run_optional_features(). Complexity reduced from 25 → 14._handle_output()refactored with_write_file()helper; nesting depth reduced from 5 → 3.generate_markdown_report()split into_md_summary_section(),_md_test_evidence_section(),_md_findings_section().generate_text_report()split into_text_project_section()and_text_single_file_section().
- Both files had
DDC = 0.00becauseBasePattern/FileAnalysiswere imported only for type annotations, whichUsageCollectorcorrectly skips. - Fix: annotation-only project imports moved under
if TYPE_CHECKING:guard. DDC now correctly classifies them as type-checking imports (excluded from usage ratio), resolving the false positive without changing runtime behavior. registry.py: addedfrom __future__ import annotations, replaced eagerglobal _global_registrylazy-init pattern with module-level eager initialization (eliminatesglobalstatement, DDC HIGH flag).question_generator.py: restoredfrom __future__ import annotations, converted Python 3.10+ union syntax (int | None,str | None,list[Q],dict[...]) toOptional[int],Optional[str],List[Q],Dict[...]for Python 3.8 compatibility.
- Self-inspection result (dogfooding on own
src/):deficit_files: 3 → 0 (cli.py 53.5→29.1, registry.py 39.5→clean, question_generator.py 30.0→clean)avg_deficit_score: 11.65 → 9.57weighted_deficit_score: 15.88 → 12.42overall_status: clean (unchanged)
- 188 tests pass; ruff + mypy clean.
- New pattern
phantom_importdetects imports referencing packages that do not exist in the current environment: not in stdlib, built-in C extensions, or installed distributions. - Resolution index built once per process from three sources:
sys.builtin_module_names— C extension modulessys.stdlib_module_names— standard library (Python 3.10+)importlib.metadata.packages_distributions()— pip-installed packages
importlib.util.find_specfallback covers namespace packages and editable installs.- Relative imports (
from . import X) excluded — local project structure is environment-dependent. - Severity: CRITICAL, Axis: QUALITY, ID:
phantom_import - Errs toward False Negative on resolution errors to avoid false positives.
- Every CLI run automatically records results to
~/.slop-detector/history.db(SQLite). - Schema:
deficit_score,ldr_score,inflation_score,ddc_usage_ratio,pattern_count,grade,git_commit,git_branch,file_hash(SHA256 prefix). - Auto-migration on first run — safe
ALTER TABLEfor schema evolution. - New CLI flags:
--show-history— per-file trend table (timestamp, deficit, LDR, patterns, grade)--history-trends— project-wide daily aggregates for last 7 days--export-history <path>— full JSONL export for ML training pipeline--no-history— opt-out from recording this run
- Trend analysis: direction indicator (improved / degraded / stable) + delta across N runs.
export_jsonl()produces training-ready JSONL forDatasetLoader.load_jsonl().
MLPipeline.run_on_real_data(): loads CodeSearchNet / the-stack / custom JSONL, applies self-supervised labelling (deficit_score >= 30 → slop), trains classifier.DatasetLoader:load_codesearchnet(),load_stack(),load_jsonl().- New extra:
pip install "ai-slop-detector[ml-data]"(scikit-learn + numpy + datasets>=2.9.0). datasetsadded tofullextra and mypy ignore list.
- README primary statement updated to reflect the project's ontology: "Catches the slop that AI produces — before it reaches production." Authorship (human / Claude / Cursor / custom agent) is irrelevant; the code speaks for itself.
history.pyfully rewritten:bcr_score→inflation_score(v2.8.0 alignment),pattern_countadded, global DB path~/.slop-detector/history.db,export_jsonl()replacesexport_history().RandomForestClassifiernow trained withclass_weight="balanced"to handle real-data class imbalance (~4% slop rate in public datasets).load_codesearchnet(): removed deprecatedtrust_remote_code=True(datasets>=4.x).pyproject.tomlversion:2.8.0→2.9.0.
--show-historyresolves relative paths to absolute before DB lookup.
god_function(HIGH): flags functions wherelogic_lines > 50ORcyclomatic_complexity > 10. Complexity computed as1 + count(If, For, While, ExceptHandler, With, BoolOp).dead_code(MEDIUM): detects statements after terminal nodes (return,raise,break,continue) in any block, includingorelse,finalbody, and exception handler bodies.deep_nesting(HIGH): detects control-flow nesting depth > 4. Depth is computed recursively overIf/For/While/With/Trybodies.- New file:
src/slop_detector/patterns/python_advanced.py patterns/__init__.pyregisters all three viaget_all_patterns()
- Full AST-based analysis: cyclomatic complexity, god function, dead code, callback hell detection — replaces regex-based heuristics when tree-sitter is available
FunctionMetricsdataclass: per-function complexity, max depth, is_god_functionJSFileAnalysisextended with:function_metrics,max_complexity,god_function_count,dead_code_count,ast_mode- Graceful fallback to regex when
tree-sitteris not installed
MLScoredataclass:slop_probability,confidence,model_type,agreement,features_usedMLScorer.from_model(path)— returnsNonesilently on missing model or missing scikit-learn; zero import overhead without the extra installedFileAnalysis.ml_scorefield (v2.8.0,Any = None)SlopDetector.__init__accepts optionalmodel_path: PathparameterMLScore.labelproperty:"slop"(>= 0.70),"uncertain"(>= 0.40),"clean"(< 0.40)- Agreement:
(deficit_score >= 30) == (slop_probability >= 0.40) - New file:
src/slop_detector/ml/scorer.py MLScore,MLScorerexported fromslop_detector.__init__
print_rich_report()single-file panel: Pattern Issues section (severity- sorted, top 10 + overflow count), Advanced summary (N god-fn, N dead-code, N deep-nest), ML Score section (probability, confidence, model_type, agreement) — shown only when model is presentlist_patterns()now includes "Python Advanced" category
- Summary diagnostic message includes ML score when
result.ml_scorepresent - Status bar tooltip includes ML confidence and label
- New pattern IDs (
god_function,dead_code,deep_nesting) automatically appear as diagnostics via existing genericpattern_idcode handler
docs/MATH_MODELS.md— comprehensive mathematical specification of all scoring formulas, thresholds, SR9 aggregation, AST models, ML feature vector, and formula change history
- New extras:
js,ml-full,full mlextra no longer includes xgboost (moved toml-full)requires-pythonraised from>=3.8to>=3.9
- Complexity now amplifies jargon penalty (
max(1.0, 1+(cc-3)/10)) instead of dividing it - Formula:
min((jargon/logic_lines) * complexity_modifier * 10, 10.0) - A function with complexity=13 receives 2x penalty vs. complexity=3
- Single monotonic axis on
deficit_scorereplaces multi-branch logic INFLATED_SIGNALthreshold:deficit_score >= 50SUSPICIOUSthreshold:deficit_score >= 30CRITICAL_DEFICITthreshold:deficit_score >= 70- Two supplementary overrides: critical-pattern count and DDC ratio
project_ldr = 0.6 * min(file_ldrs) + 0.4 * mean(file_ldrs)- Worst file weighted 60% to prevent masking by majority of clean files
- Justification scope changed from file-level to per-function scope
- Scope includes decorator lines (
scope_start = min(decorator.lineno)) - One import no longer justifies jargon across the entire file
bcr_scorerenamed toinflation_score- 3 new features added:
god_function_count,dead_code_count,deep_nesting_count - Total: 16 features (was 13)
- Explicit
bool(),float(),int()casts for JSON serialization
- Docstring inflation diagnostics: Line-level detection from
docstring_inflation.details[]with severity mapping (critical -> Error, warning -> Warning) - Context jargon evidence diagnostics: Flags unjustified claims from
context_jargon.evidence_details[]whereis_justified === false - Hallucinated dependency diagnostics: Surfaces
hallucination_deps.hallucinated_deps[]as Info-level diagnostics - Pattern fix suggestions: Appends
suggestionfield to pattern issue messages when present - Lint-on-type debounce: 1500ms debounce timer prevents excessive analysis during typing
- LDR grade in status bar: Tooltip now displays
LDR Grade: {grade}
- VS Code extension surfaces ~95% of CLI JSON output (up from ~40%)
- Version alignment:
pyproject.toml,__init__.py,package.jsonall at 2.7.0
- run_scan ignore handling:
run_scan.pynow applies configured ignore patterns before file analysis. - Fixture exclusion consistency: Paths matched by config ignore rules (for example
tests/**) are excluded from scanner input. - Scan/report alignment:
run_scan.pybehavior now aligns withSlopDetector.analyze_project()path filtering.
- Pattern matching implementation: Added normalized path matching with
fnmatch, including compatibility handling for**/prefixes.
Core Feature: Allow developers to explicitly whitelist intentional complexity, shifting responsibility from the tool to the sovereign developer.
- New decorator:
@slop.ignore(reason="...", rules=[...])to mark functions as intentionally complex - Reason required: All ignored functions must provide explanation
- Selective rules: Optionally ignore specific rules only (LDR, INFLATION, DDC, PLACEHOLDER)
- AST detection: Decorator detected at analysis time, not runtime
- Filtered issues: Pattern issues inside ignored functions are excluded from reports
- Playground directories:
playground/,labs/,experiments/,prototypes/,sandbox/now exempt from strict analysis - Configuration: New
consent_complexitysection in.slopconfig.yaml - Report tracking: Ignored functions logged in "Whitelisted Complexity" section
import slop
@slop.ignore(reason="Bitwise optimization for O(1) performance")
def fast_inverse_sqrt(number):
# Complex but intentional implementation
i = 0x5f3759df - (number >> 1)
return i
@slop.ignore(reason="Domain algorithm", rules=["LDR"])
def complex_calculation():
# Only LDR check ignored, other rules still apply
...- Version alignment: Unified version to 2.6.3 (was incorrectly showing 3.0.0)
- FileAnalysis model: Added
ignored_functionsfield - Pattern detection: Now filters issues from ignored function ranges
- New files:
src/slop_detector/decorators.py(decorator implementation)tests/test_ignore_pattern.py(10 test cases)
- Modified files:
src/slop_detector/core.py(+100 lines: AST detection, filtering)src/slop_detector/models.py(+15 lines: IgnoredFunction dataclass)src/slop_detector/__init__.py(exports).slopconfig.example.yaml(new sections)
"Rules should be the soil for the dream to grow, not the cage that kills it."
This release implements the "Dream-Saver Protocol" from SIDRCE_SLOP_EVOLUTION_PLAN.md, ensuring that innovation is not killed by overly strict enforcement.
Thanks to @OnlineProxy for the critical feedback: "CI is green, but 0 integration tests" — This release addresses exactly that gap.
- Split test evidence:
tests→tests_unit+tests_integration - 4-layer detection:
- Path-based:
tests/integration/,e2e/,it/ - File name:
test_integration_*.py,*_integration_test.py - Pytest markers:
@pytest.mark.integration,@pytest.mark.e2e - Runtime signals:
TestClient,testcontainers,docker-compose
- Path-based:
- Enhanced EVIDENCE_REQUIREMENTS:
production-ready: Now requires bothtests_unitANDtests_integrationenterprise-grade: Now requires both test typesscalable: Now requirestests_integrationfault-tolerant: Now requirestests_integration
- False positive prevention:
_is_real_test_file()excludes helper files
- Markdown reports: New "Test Evidence Summary" section
- Table showing unit vs integration test breakdown
- Warning when integration tests missing but production claims exist
- Text reports: Test statistics in project summary
- Enhanced questions: Human-readable evidence names
tests_integration→ "integration tests"- Special note: "Integration tests are critical for production claims"
- Configuration Extension:
.slopconfig.yamlsupport for integration test detection- Customizable dir/file patterns, pytest markers, runtime signals
- Quality claims validation requirements (production_ready, enterprise_grade, scalable, fault_tolerant)
- CI Gate Claim-Based Mode:
--ci-claims-strictflag- Fails build if production/enterprise/scalable/fault-tolerant claims lack integration tests
- Integrates with existing soft/hard/quarantine modes
- Evidence tracking: 14 types → 15 types (split tests into unit/integration)
- Context-jargon coverage: 74% → 95% (+21%)
- Question readability: Raw evidence names replaced with formatted versions
- Tests: 170/170 passed (165 existing + 5 new)
- Coverage: 85% overall
- New files:
tests/test_integration_evidence.py(5 tests)
- Modified files:
src/slop_detector/metrics/context_jargon.py(+47 lines)src/slop_detector/cli.py(+43 lines)src/slop_detector/question_generator.py(+14 lines)README.md(updated evidence list)
Special thanks to community feedback that drives these improvements. This release demonstrates responsive development based on real-world usage patterns.
- Configuration Sovereignty: Externalized CATEGORY_MAP and INTENT_PATTERNS to
src/slop_detector/config/known_deps.yaml - Question Generator Tests: Comprehensive test suite with 8 test cases
- VS Code Extension: Synchronized to v2.6.1
- Hallucination Dependencies: Refactored to load configuration dynamically from YAML
- Test Coverage: Increased from 43% to 85% (overall), question_generator.py: 11% → 88%
- Import Issues: Resolved test import conflicts
- Documentation: Updated all version references to 2.6.1
- Date Consistency: Unified all dates to 2026-01-12
- Tests: 165/165 passed (100% pass rate)
- Coverage: 85% overall (target: 80%, achieved: +5%)
- New Module Coverage: 88-92% (all above 90% target)
- context_jargon.py: 91%
- docstring_inflation.py: 89%
- question_generator.py: 88%
- hallucination_deps.py: 92%
- Evidence-based validation for quality claims (production-ready, enterprise-grade, etc.)
- 14 evidence types: error_handling, logging, tests, input_validation, config_management, monitoring, documentation, security, caching, async_support, retry_logic, design_patterns, advanced_algorithms, optimization
- Justification ratio:
justified_claims / total_claims - Missing evidence reporting: Specific feedback on what's lacking per claim
- Cross-validation of buzzwords against actual codebase artifacts
- Ratio-based detection:
docstring_lines / implementation_lines - Severity levels: CRITICAL (>=2.0x), WARNING (>=1.0x), INFO (>=0.5x)
- Per-entity tracking: Functions, classes, and modules analyzed separately
- File-level aggregation: Overall ratio and top 10 offenders
- Detects AI-generated documentation without substance
- 5 new patterns added:
NotImplementedPattern(HIGH) - Functions raising NotImplementedErrorEmptyExceptPattern(CRITICAL) - Empty exception handlersReturnNonePlaceholderPattern(MEDIUM) - Functions only returning NoneInterfaceOnlyClassPattern(MEDIUM) - Classes with 75%+ placeholder methodsEllipsisPlaceholderPattern(HIGH) - Ellipsis-only functions
- Total: 14 placeholder patterns across 4 severity tiers
- Integration with existing pattern detection system
- 12 purpose categories: ML, Vision, HTTP, Database, Async, Data, Serialization, Testing, Logging, CLI, Cloud, Security
- 60+ libraries tracked across categories
- Category-level usage analysis: Detects unused ML stack, HTTP libs, etc.
- Intent inference: "Why was this dependency added?"
- Per-library and per-category reporting
- Actionable review questions instead of raw scores
- 3 severity levels: Critical, Warning, Info
- Context-aware phrasing: Line numbers, specific evidence, intent
- Examples:
- "Why import 'torch' for ML but never use it?"
- "'production-ready' claim lacks: error_handling, logging, tests"
- "Function has 15 lines of docstring, 2 lines of code"
- Integrated into CLI output with Rich formatting
- Soft Mode: PR comments only, never fails (informational)
- Hard Mode: Fail build on thresholds (strict enforcement)
- Quarantine Mode: Track repeat offenders, escalate after 3 violations
- Configurable thresholds: deficit_score, pattern counts, inflation, DDC
- Persistent tracking:
.slop_quarantine.jsondatabase - GitHub Action examples provided
- CLI flags:
--ci-mode,--ci-report
- Improved exception handling: Specific exceptions instead of broad catch
- Added encoding specifications: UTF-8 for all file I/O operations
- Removed unused imports: Cleaned up ci_gate.py, question_generator.py
- Broad exception catching in quarantine DB load/save
- Missing encoding in file operations
- Unused variable in pattern question generation
- Files added: 7 (ci_gate.py, docstring_inflation.py, hallucination_deps.py, context_jargon.py + 3 test files)
- Lines of code: ~2,500 new lines
- Test coverage: 68% overall, 90%+ for new modules
- Pylint score: 9.30/10
- All tests: 58/58 passed
- Type Hint Detection: Implemented proper
_is_in_annotation()using NodeVisitor pattern for accurate import usage detection - API Compatibility: Migrated
run_scan.pyto v2.x API (was using deprecated v1.x API) - Type Safety: Enabled mypy type checking (removed
ignore_errors = true) - Code Quality: Removed dead code and unnecessary return statements
- Comprehensive CLI Tests: 58 test cases covering all CLI functionality (JSON, HTML, Markdown outputs)
- Test Coverage: Achieved 80% coverage on core modules (up from 26%)
- Coverage Measurement: Focused on core modules (excluded enterprise features in beta)
- Documentation: Updated badges and status to reflect actual metrics
- ASCII Safety: Replaced emoji markers with ASCII equivalents in
run_scan.py
- Polyglot architecture with LanguageAnalyzer interface
- Pattern refinement for anti-pattern detection
- Professional terminology (Deficit, Inflation, Jargon)
- Python-focused quality analysis
- Re-architected
src/slop_detector/languageswithLanguageAnalyzerinterface - Robust
PythonAnalyzerimplementation - Pattern-based detection system
- Renamed metrics for clarity: Slop→Deficit, Hype→Inflation/Jargon
- Removed conflicting
slop_detector.pyfrom root
- Obfuscated regex patterns to prevent self-detection of TODO/FIXME tags
- FastAPI Server: Production-ready REST API with OpenAPI docs
- Endpoints:
POST /analyze/file: Analyze single file with history trackingPOST /analyze/project: Full project analysis (async background tasks)GET /history/file/{path}: Get file analysis historyGET /trends/project: Quality trends over timePOST /webhook/github: GitHub push event handlerGET /status/project/{id}: Real-time project status
- Auto-documentation: Swagger UI at
/docs, ReDoc at/redoc - CORS Support: Cross-origin requests for dashboard integration
- Real-time Monitoring: Auto-refresh every 30 seconds
- Visualizations:
- Overall quality score across all projects
- Total files monitored
- Critical issues count
- 30-day quality trend chart (Chart.js)
- Project List: Quick overview with scores and grades
- Alert System: Recent warnings and critical issues
- Dark Theme: Developer-friendly UI with Tailwind-inspired design
- ASCII-safe Icons: Cross-platform compatible symbols
- Webhook Handler: Automatic analysis on push events
- Changed Files Detection: Only analyze modified/added files
- Status Updates: Post analysis results back to GitHub
- Branch Filtering: Configure which branches to monitor
- New Command:
slop-apito start REST API server - Server Config:
--host,--port,--configoptions - Background Mode: Detached server execution
- Dependencies: Added FastAPI, Uvicorn, Pydantic
- Architecture: Separated API layer from core logic
- Data Models: Pydantic models for request/response validation
- Performance: Async/await for non-blocking operations
- Scalability: Background tasks for heavy operations
- Security: HMAC signature validation for webhooks (production)
- Monitoring: Health endpoint for uptime checks
- HistoryTracker: SQLite-based analysis history storage
- Regression Detection: Automatic detection when scores worsen
- Trend Analysis: Project-wide quality trends over time
- File-level History: Track individual file evolution
- Export Capability: Export history to JSON for external analysis
- GitIntegration: Extract commit/branch info automatically
- Pre-commit Hook: Automatic quality detection before commits
- Staged Files Detection: Only analyze files being committed
- Fail on Regression: Block commits with quality degradation
- Real-time Linting: Analyze on save or while typing
- Inline Diagnostics: Show warnings/errors directly in editor
- Status Bar Integration: Quick quality overview
- Commands:
- Analyze Current File
- Analyze Workspace
- Show File History
- Install Git Pre-Commit Hook
- Configuration: Customizable thresholds, auto-lint settings
- Multi-language: Python, JavaScript, TypeScript support
--record-history: Store analysis results in history DB--show-history: Display file analysis history--fail-on regression: Exit with error on quality degradation--install-git-hook: Setup pre-commit hook automatically
- History database stored in
.slop_history.dbby default - CLI now supports history-aware operations
- Improved error messages for missing dependencies
- Git repository detection on Windows
- File hash calculation for large files
- Thread-safety for concurrent history writes
- SlopClassifier: ML-based quality detection with ensemble models
- Training Data Collection: Automatic data collection from high-quality repos
- Model Support:
- RandomForest: Baseline ensemble model
- XGBoost: Gradient boosting for improved accuracy
- Ensemble: Combines RF + XGBoost via voting
- Performance Targets Achieved:
- Accuracy: >90% on test set
- Precision: >85% (minimizes false positives)
- Recall: >95% (catches most deficits)
- F1-Score: >90%
- 15 ML Features:
- Metric-based: LDR, ICR, DDC scores
- Pattern-based: Critical/High/Medium/Low pattern counts
- Code-quality: Avg function length, comment ratio, complexity
- Cross-language patterns, hallucination count
- Volume metrics: Total lines, logic lines, empty lines
- TrainingDataCollector: Clones and analyzes GitHub repos
- Good Data Sources: NumPy, Flask, Django, Requests, CPython
- Bad Data Sources: Known low-quality repositories
- Dataset Format: JSON with features and labels
- Model Persistence: Pickle-based save/load
--mlflag to enable ML-based detection--ml-model <path>to specify custom trained model--confidence-thresholdfor ML prediction filtering- ML confidence score in output
pip install ai-slop-detector[ml]for ML support- scikit-learn, xgboost, numpy as extras
- Training data module:
slop_detector/ml/training_data.py - Classifier module:
slop_detector/ml/classifier.py - Feature extraction from file analysis results
- Cross-validation support
- Feature importance analysis
- ML training guide in README
- Feature engineering documentation
- Model performance benchmarks
- Pattern Registry: Extensible system for managing detection patterns
- 23 Detection Patterns:
- 6 Structural patterns (bare_except, mutable_default_arg, star_import, global_statement, exec_eval, assert)
- 5 Placeholder patterns (pass, TODO, FIXME, HACK, ellipsis)
- 12 Cross-language patterns (JavaScript, Java, Ruby, Go, C#, PHP)
- Hybrid Scoring: Combines metric-based (LDR/ICR/DDC) with pattern-based detection
- Pattern Penalties: Critical=10pts, High=5pts, Medium=2pts, Low=1pt (capped at 50pts)
- Pre-commit Hooks: Full integration with
.pre-commit-hooks.yaml - CLI Enhancements:
--list-patternsto show all available patterns--disable <pattern_id>to disable specific patterns--patterns-onlyto skip metrics and only run patterns
- Configuration Examples:
CONFIG_EXAMPLES.mdwith pyproject.toml examples
SlopDetectornow includes pattern detection alongside metricsFileAnalysismodel includespattern_issuesfield- Deficit score calculation includes pattern penalties
- Config system supports
patterns.disabledlist - README updated with v2.1.0 features and examples
- Pattern base classes:
BasePattern,ASTPattern,RegexPattern - Pattern registry with enable/disable functionality
- 8 unit tests for pattern detection
- Test corpus with 30+ code examples (good and bad)
- Documentation: CONFIG_EXAMPLES.md for setup guides
- Pattern Registry: Extensible system for managing detection patterns
- 23 Detection Patterns:
- 6 Structural patterns (bare_except, mutable_default_arg, star_import, global_statement, exec_eval, assert)
- 5 Placeholder patterns (pass, TODO, FIXME, HACK, ellipsis)
- 12 Cross-language patterns (JS, Java, Ruby, Go, C#, PHP)
- Hybrid Scoring: Combines metric-based (LDR/ICR/DDC) with pattern-based detection
- Pattern Penalties: Critical=10pts, High=5pts, Medium=2pts, Low=1pt (capped at 50pts)
- Test Corpus: 3 corpus files with good/bad code examples
- Configuration: Pattern enable/disable via config file
SlopDetectornow includes pattern detection alongside metricsFileAnalysismodel includespattern_issuesfield- Deficit score calculation includes pattern penalties
- Config system supports
patterns.disabledlist
- Pattern base classes:
BasePattern,ASTPattern,RegexPattern - Pattern registry with enable/disable functionality
- 8 unit tests for pattern detection
- Test corpus with 30+ code examples
- Metric-based architecture: LDR, ICR, DDC calculators
- YAML configuration system:
.slopconfig.yamlwith deep customization - Context-aware jargon detection: Justification checking (e.g., "neural" OK if torch used)
- Docker support: Production Dockerfile + docker-compose.yml
- GitHub Actions CI/CD: Full pipeline (test, lint, docker, publish)
- HTML report generation: Rich visual reports with charts
- Weighted project analysis: Files weighted by LOC
- TYPE_CHECKING awareness: Type hint imports excluded from DDC
- Formula-based scoring: Configurable weights (LDR: 40%, ICR: 30%, DDC: 30%)
- Environment variable support:
SLOP_CONFIGfor config path
-
LDR (Logic Density Ratio): Measures actual logic vs empty shells
- Empty patterns:
pass,...,return None,raise NotImplementedError,# TODO - ABC interface exception (50% penalty reduction)
- Type stub file support (
.pyi) - Thresholds: S++ (0.85+), A (0.60+), C (0.30+), F (0.15-)
- Empty patterns:
-
ICR (Inflation-to-Code Ratio): Technical jargon vs implementation complexity
- 60+ jargon terms tracked (AI/ML, architecture, quality, academic)
- Radon integration for accurate complexity
- Config file exception (ICR = 0.0 for settings files)
- Context-aware justification (jargon OK if backed by code)
- Thresholds: PASS (<0.5), WARNING (0.5-1.0), FAIL (>1.0)
-
DDC (Deep Dependency Check): Imported vs actually used libraries
- TYPE_CHECKING block detection
- Heavyweight library identification (torch, tensorflow, numpy, etc.)
- Usage ratio:
actually_used / imported - Thresholds: EXCELLENT (0.90+), ACCEPTABLE (0.50+), SUSPICIOUS (0.30-)
- Single file analysis mode
- Project analysis mode (
--projectflag) - JSON output support (
--jsonflag) - HTML report generation (
--output report.html) - Custom config file (
--config) - Fail threshold for CI/CD (
--fail-threshold) - Verbose debug output (
--verbose) - Version flag (
--version)
- Dependencies: pyyaml, radon, jinja2
- Python support: 3.8, 3.9, 3.10, 3.11, 3.12
- Build system: Modern pyproject.toml
- Testing: Unit tests for LDR, ICR, DDC modules
- Single-pass AST analysis: Read file once, parse once
- Documentation: Comprehensive README, CONTRIBUTING, CHANGELOG
| Version | Date | Focus | Status |
|---|---|---|---|
| 3.0.2 | 2026-03-15 | Phantom import 3-tier classification, LDR packaging init fix, god_function LOW path, placeholder precision | [+] Current |
| 3.0.1 | 2026-03-10 | ReturnConstantStubPattern, configurable god_function thresholds + domain_overrides | [+] Released |
| 3.0.0 | 2026-03-09 | GQG scoring, DCF fingerprint, MST H0 VR coherence | [+] Released |
| 2.9.3 | 2026-03-09 | Self-calibration engine | [+] Released |
| 2.9.2 | 2026-03-09 | Rich 3-panel single-file UI reconnected | [+] Released |
| 2.9.1 | 2026-03-08 | Self-inspection patch, DDC false positive fix | [+] Released |
| 2.9.0 | 2026-03-08 | PhantomImportPattern, history auto-tracking | [+] Released |
| 2.8.0 | 2026-03-07 | Python advanced patterns, JS tree-sitter, ML secondary signal | [+] Released |
| 2.7.0 | 2026-02-12 | VS Code extension full diagnostic surface | [+] Released |
| 2.6.x | 2026-01-12 | Consent-based complexity, integration test evidence, config sovereignty | [+] Released |
| 2.0.0 | 2026-01-08 | Initial production release | [+] Released |
- Stdlib fallback for radon: Will become optional dependency
- Text-only output: HTML will be default
- Flamehaven Labs - Core development
- Community - Bug reports and feature requests
- PyPI: https://pypi.org/project/ai-slop-detector
- GitHub: https://github.com/flamehaven/ai-slop-detector
- Docker Hub: https://hub.docker.com/r/flamehaven/ai-slop-detector
- Documentation: (Coming soon)
- Major (X.0.0): Breaking changes, architectural rewrites
- Minor (X.Y.0): New features, non-breaking changes
- Patch (X.Y.Z): Bug fixes, documentation updates
- Major releases: Quarterly (Q1, Q2, Q3, Q4)
- Minor releases: Monthly
- Patch releases: As needed
Last Updated: 2026-03-15 Current Version: 3.0.2 Status: Production Ready