AI Slop Code Risk Monitor

advplyr/audiobookshelf

SlopCodeMonitor badge for advplyr/audiobookshelf Adjusted legacy signal; badge bands: 25 / 50 / 75 (different from dashboard bands).

Self-hosted audiobook and podcast server

0.9 Low pattern signal View on GitHub

Open-Source Code Quality, Security and Technical Debt Review

This report summarizes scanner evidence for advplyr/audiobookshelf, a JavaScript project with 14,868 GitHub stars. SynthScan examined 218,902 lines of code across 819 source files, recording 140 pattern matches distributed across 10 syntactic categories. The legacy adjusted pattern signal is 0.9 (Low pattern signal); it is not an authorship estimate.

Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.

0.9
Adjusted Signal
0.9
Raw Pattern Score
100%
Time Factor
2026-10-23
Last Push
14.9K
Stars
JavaScript
Language
218.9K
Lines of Code
819
Files
140
Pattern Hits
2026-10-31
Scan Date
0.00
HC Hit Rate

Risk Review · Payload v1

Use each vector to guide manual verification of the underlying findings.

Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.

Cognitive Ownership Risk 2.5/100 · LOW

Can maintainers explain intent, assumptions, and trade-offs? 84 finding(s).

Hallucinated Dependency & Supply Chain Risk 2.0/100 · LOW

Are imports declared and package/API names verified? 56 finding(s).

Agent Over-Engineering Ratio 0.4/100 · LOW

Are wrappers, guards, and repeated structures necessary? 16 finding(s).

PR Review Velocity Impact 3.9/100 · LOW

Which changes need focused human review? 140 finding(s).

What These Metrics Mean

Adjusted Signal
Legacy pattern score normalized per 1,000 scanned lines and multiplied by the repository-level time factor. It is not an estimate of AI authorship.
Raw Pattern Score
Sum of severity- and context-weighted pattern findings before applying the time factor.
Time Factor
A coarse multiplier based on repository last-push metadata. It does not identify when individual code was written.
Pattern Hits
Count of configured pattern findings. Review each location and surrounding code before acting.
HC Hit Rate
High- and critical-severity findings per scanned file. Severity is a configured detector weight, not proof of a vulnerability or authorship.
Lines / Files
Scan coverage denominators used by the legacy normalized score.

Pattern-Signal History

This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.

Severity Breakdown

Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.

CRITICAL 2HIGH 1MEDIUM 5LOW 132

Directory Score Breakdown

This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.

Pattern Findings

The scanner identified 140 distinct pattern matches across 10 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.

Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.

Fake / Example Data53 hits · 65 pts
SeverityFileLineSnippetContext
LOWtest/server/utils/ffmpegHelpers.test.js15 artist: 'John Doe',CODE
LOW⚡test/server/utils/parsers/parseNameString.test.js24 expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])CODE
LOW⚡test/server/utils/parsers/parseNameString.test.js29 expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])CODE
LOW⚡test/server/utils/parsers/parseNameString.test.js34 expect(result.names).to.deep.equal(['John Smith', 'Jane Doe', 'John Doe'])CODE
LOW⚡test/server/utils/parsers/parseNameString.test.js34 expect(result.names).to.deep.equal(['John Smith', 'Jane Doe', 'John Doe'])CODE
LOW⚡test/server/utils/parsers/parseNameString.test.js39 expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])CODE
LOW⚡test/server/utils/parsers/parseNameString.test.js44 expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])CODE
LOW⚡test/server/finders/BookFinder.test.js405 const bookResults = [{ duration: 10, title: 'The Great Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js407 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js416 const bookResults = [{ duration: 21, title: 'The Great Novel', author: 'John Doe' }] // 21 min, diff = 11 minCODE
LOW⚡test/server/finders/BookFinder.test.js418 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js427 const bookResults = [{ duration: 16, title: 'The Great Novel', author: 'John Doe' }] // 16 min, diff = 6 minCODE
LOW⚡test/server/finders/BookFinder.test.js429 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js438 const bookResults = [{ duration: 14, title: 'The Great Novel', author: 'John Doe' }] // 14 min, diff = 4 minCODE
LOW⚡test/server/finders/BookFinder.test.js440 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js449 const bookResults = [{ duration: 11, title: 'The Great Novel', author: 'John Doe' }] // 11 min, diff = 1 minCODE
LOW⚡test/server/finders/BookFinder.test.js451 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js460 const bookResults = [{ duration: 10, title: 'The Great Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js462 const results = await bookFinder.search({ media: {} }, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js469 const bookResults = [{ title: 'The Great Novel', author: 'John Doe' }] // No duration in bookCODE
LOW⚡test/server/finders/BookFinder.test.js471 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js478 const bookResults = [{ duration: 10, title: 'Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js484 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'Novel Ex', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js508 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js515 const bookResults = [{ duration: 10, title: 'The Great Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js524 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js533 const bookResults = [{ duration: 10, title: 'The Great Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js542 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js554 const bookResults = [{ duration: 10, title: 'The Great Novel', subtitle: 'A Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js556 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel: A Novel', 'John CODE
LOW⚡test/server/finders/BookFinder.test.js561 const bookResults = [{ duration: 10, title: 'The Great Novel', subtitle: 'A Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js563 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOW⚡test/server/finders/BookFinder.test.js569 const bookResults = [{ duration: 10, title: 'The Great Novel', author: 'John Doe' }]CODE
LOW⚡test/server/finders/BookFinder.test.js572 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel - A Novel', 'JoCODE
LOW⚡test/server/finders/BookFinder.test.js577 const bookResults = [{ duration: 10, title: 'The Great Novel', author: 'John Doe' }]CODE
LOWtest/server/finders/BookFinder.test.js589 const bookResults = [{ title: 'The Great Novel', author: 'John Doe' }]CODE
LOWtest/server/finders/BookFinder.test.js591 const results = await bookFinder.search(libraryItemPerfectDuration, provider, 'The Great Novel', 'John Doe')CODE
LOWclient/cypress/tests/components/cards/AuthorCard.cy.js10 name: 'John Doe',CODE
LOWclient/cypress/tests/components/cards/AuthorCard.cy.js79 .and('have.text', 'John Doe')CODE
LOWclient/cypress/tests/components/cards/AuthorCard.cy.js137 $post: cy.stub().resolves({ updated: false, author: { name: 'John Doe' } })CODE
LOWclient/cypress/tests/components/cards/AuthorCard.cy.js159 $post: cy.stub().resolves({ updated: true, author: { name: 'John Doe' } })CODE
LOWclient/cypress/tests/components/cards/AuthorCard.cy.js181 $post: cy.stub().resolves({ updated: true, author: { name: 'John Doe', imagePath: 'path/to/image' } })CODE
LOW…ient/cypress/tests/components/cards/NarratorCard.cy.js5 name: 'John Doe',CODE
LOW…ient/cypress/tests/components/cards/NarratorCard.cy.js36 cy.get('&name').should('have.text', 'John Doe')CODE
LOW…ient/cypress/tests/components/cards/NarratorCard.cy.js47 let propsData = { narrator: { name: 'John Doe', numBooks: 1 }, width: 200, height: 150 }CODE
LOW⚡client/cypress/tests/components/cards/ItemSlider.cy.js8 { name: 'John Doe', numBooks: 5 },CODE
LOW⚡client/cypress/tests/components/cards/ItemSlider.cy.js9 { name: 'Jane Doe', numBooks: 3 },CODE
LOW⚡client/cypress/tests/components/cards/ItemSlider.cy.js14 { id: 1, name: 'John Doe', numBooks: 5 },CODE
LOW⚡client/cypress/tests/components/cards/ItemSlider.cy.js15 { id: 2, name: 'Jane Doe', numBooks: 3 },CODE
LOWclient/components/ui/TextInput.vue3 <input :id="inputId" :name="inputName" ref="input" v-model="inputValue" :type="actualType" :step="step" :min="min" :CODE
LOWclient/components/ui/TextareaInput.vue2 <textarea ref="input" v-model="inputValue" :rows="rows" :readonly="readonly" :disabled="disabled" :placeholder="placehCODE
LOWclient/components/ui/EditableText.vue2 <input ref="input" v-model="inputValue" :type="type" :readonly="readonly" :disabled="disabled" :placeholder="placeholdCODE
LOWclient/components/ui/VueTrix.vue34 <trix-editor :toolbar="toolbarId" :contenteditable="!disabledEditor" :class="['trix-content']" ref="trix" :input="coCODE
Over-Commented Block44 hits · 44 pts
SeverityFileLineSnippetContext
LOWdocker-compose.yml1### EXAMPLE DOCKER COMPOSE ###COMMENT
LOWdocker-compose.yml21 # you are running ABS onCOMMENT
LOWserver/providers/FantLab.js1const axios = require('axios')COMMENT
LOWserver/libs/async/index.js1//COMMENT
LOWserver/libs/umzug/storage/json.js61//# sourceMappingURL=json.js.mapCOMMENT
LOW…ver/libs/archiver/archiverUtils/stringDecoder/index.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOWserver/libs/archiver/archiverUtils/minimatch/index.js101// a{b,c}d -> abd acdCOMMENT
LOWserver/libs/archiver/archiverUtils/minimatch/index.js281 if (p === false) return falseCOMMENT
LOWserver/libs/archiver/archiverUtils/minimatch/index.js301 // - matchOne(b/x/y/z/c, b/**/c)COMMENT
LOWserver/libs/archiver/archiverUtils/minimatch/index.js381 // If the file ends in /, then it can only match aCOMMENT
LOWserver/libs/archiver/archiverUtils/minimatch/index.js601 // a right bracket shall lose its specialCOMMENT
LOW…r/libs/archiver/archiverUtils/readableStream/stream.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…erUtils/readableStream/internal/streams/passthrough.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…hiverUtils/readableStream/internal/streams/readable.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…hiverUtils/readableStream/internal/streams/readable.js401 // 2. If that resulting state will trigger a _read, then call _read.COMMENT
LOW…hiverUtils/readableStream/internal/streams/readable.js541// it's in progress.COMMENT
LOW…hiverUtils/readableStream/internal/streams/readable.js561 // - No data in the buffer, and the stream is in flowing mode. In this modeCOMMENT
LOW…hiverUtils/readableStream/internal/streams/writable.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…iverUtils/readableStream/internal/streams/transform.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…iverUtils/readableStream/internal/streams/transform.js21// a transform stream is a readable/writable stream where you doCOMMENT
LOW…iverUtils/readableStream/internal/streams/transform.js41// _read(n) is called, it transforms the queued up data, calling theCOMMENT
LOW…rchiverUtils/readableStream/internal/streams/duplex.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOWserver/libs/archiver/archiverUtils/glob/index.js1// Approach:COMMENT
LOWserver/libs/archiver/archiverUtils/glob/index.js21// // by pruning it out, and testing the resulting patternCOMMENT
LOWserver/libs/archiver/archiverUtils/fsRealpath/old.js1/* istanbul ignore file - tested in node */COMMENT
LOW…/lazystream/readable-stream/lib/_stream_passthrough.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…ls/lazystream/readable-stream/lib/_stream_transform.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…ls/lazystream/readable-stream/lib/_stream_transform.js21COMMENT
LOW…ls/lazystream/readable-stream/lib/_stream_transform.js41// In a transform stream, the written data is placed in a buffer. WhenCOMMENT
LOW…Utils/lazystream/readable-stream/lib/_stream_duplex.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…ils/lazystream/readable-stream/lib/_stream_readable.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…ils/lazystream/readable-stream/lib/_stream_readable.js401 }COMMENT
LOW…ils/lazystream/readable-stream/lib/_stream_writable.js1// Copyright Joyent, Inc. and other Node contributors.COMMENT
LOW…ils/lazystream/readable-stream/lib/_stream_writable.js141 // when 'finish' is emittedCOMMENT
LOWserver/libs/libarchive/wasm-module.js161 // void * archive_open( const void * buffer, size_t buffer_size)COMMENT
LOWserver/libs/sanitizeHtml/index.js81COMMENT
LOWserver/libs/sanitizeHtml/index.js381 // Chrome accepts \ as a substitute for / in the // at theCOMMENT
LOWserver/libs/sanitizeHtml/index.js421 }COMMENT
LOWserver/libs/sanitizeHtml/index.js441 // if (!parsed.length) {COMMENT
LOWserver/libs/sanitizeHtml/index.js481 if (a === 'style') {COMMENT
LOWserver/libs/fsExtra/remove/rimraf.js61// Two possible strategies.COMMENT
LOWserver/finders/BookFinder.js461 */COMMENT
LOWclient/cypress/support/component.js1// ***********************************************************COMMENT
LOWclient/cypress/support/commands.js1// ***********************************************COMMENT
Hallucination Indicators2 hits · 20 pts
SeverityFileLineSnippetContext
CRITICALclient/components/cards/LazyBookCard.vue549 subitems: this.store.state.libraries.ereaderDevices.map((d) => {CODE
CRITICALclient/static/libs/marked/index.js6 !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?deCODE
Modern AI Meta-Vocabulary4 hits · 18 pts
SeverityFileLineSnippetContext
MEDIUM⚡…er/compress-commons/archivers/archive-output-stream.js32 // scaffold onlyCOMMENT
MEDIUM⚡…er/compress-commons/archivers/archive-output-stream.js36 // scaffold onlyCOMMENT
MEDIUM⚡…er/compress-commons/archivers/archive-output-stream.js46 // scaffold onlyCOMMENT
MEDIUM⚡…er/compress-commons/archivers/archive-output-stream.js50 // scaffold onlyCOMMENT
Verbosity Indicators10 hits · 16 pts
SeverityFileLineSnippetContext
LOWserver/managers/MigrationManager.js118 // Step 3: If migration fails, save the failed original and restore the backupCOMMENT
LOW⚡server/utils/scandir.js49 // Step 1: Filter out non-book-media files in root dir (with depth of 0)COMMENT
LOW⚡server/utils/scandir.js54 // Step 2: Separate media files and other filesCOMMENT
LOWserver/utils/scandir.js68 // Step 3: Group media files (or non-media files if includeNonMediaFiles is true) in library itemsCOMMENT
LOWserver/utils/scandir.js102 // Step 4: Add other files into library item groupsCOMMENT
LOWserver/utils/queries/libraryItemsBookFilters.js852 // Step 1: Get the first book of every series that hasnt been started yetCOMMENT
LOWserver/utils/queries/libraryItemsBookFilters.js996 // Step 3: Map books to library itemsCOMMENT
LOW…ver/libs/archiver/archiverUtils/stringDecoder/index.js233// number of bytes available, we need to check if we end on a leading/highCOMMENT
LOW…hiverUtils/readableStream/internal/streams/readable.js840 // We need to check if there is someone still listening toCOMMENT
LOW…hiverUtils/readableStream/internal/streams/readable.js858 // We need to check if there is someone still listening toCOMMENT
Hyper-Verbose Identifiers16 hits · 16 pts
SeverityFileLineSnippetContext
LOWserver/utils/podcastUtils.js78function extractFirstArrayItemString(json, key) {CODE
LOWserver/utils/ffmpegHelpers.js302async function addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, progressCB = nCODE
LOW⚡server/utils/scandir.js48function groupFileItemsIntoLibraryItemDirs(mediaType, fileItems, audiobooksOnly, includeNonMediaFiles = false) {CODE
LOWserver/utils/parsers/parseOverdriveMediaMarkers.js6function cleanOverdriveMediaMarkers(overdriveMediaMarkers) {CODE
LOWserver/utils/parsers/parseOverdriveMediaMarkers.js63function objectValuesArrayToString(arrayOfObjects) {CODE
LOWserver/libs/nodeStreamZip/index.js224 function readCentralDirectoryComplete() {CODE
LOWserver/libs/requestIp/index.js16function getClientIpFromXForwardedFor(value) {CODE
LOWserver/libs/umzug/storage/mongodb.js4function isMongoDBCollectionOptions(arg) {CODE
LOW…hiverUtils/readableStream/internal/streams/readable.js756 return function pipeOnDrainFunctionResult() {CODE
LOWserver/libs/libarchive/wasm-libarchive.js11 var Module = typeof libarchive !== "undefined" ? libarchive : {}; var moduleOverrides = {}; var key; for (key in MCODE
LOWserver/controllers/LibraryItemController.js48function ensureUserCanAccessLibraryItemsForBatch(req, res, libraryItems) {CODE
LOWserver/scanner/LibraryScanner.js657async function findLibraryItemByItemToItemInoMatch(libraryId, fullPath) {CODE
LOWserver/scanner/LibraryScanner.js668async function findLibraryItemByItemToFileInoMatch(libraryId, fullPath, isSingleMedia) {CODE
LOWserver/scanner/LibraryScanner.js690async function findLibraryItemByFileToItemInoMatch(libraryId, fullPath, isSingleMedia, itemFiles) {CODE
LOWclient/components/ui/VueTrix.vue48function enableBreakParagraphOnReturn() {CODE
LOWclient/static/libarchive/wasm-gen/libarchive.js8 var Module = typeof libarchive !== "undefined" ? libarchive : {}; var moduleOverrides = {}; var key; for (key in MCODE
Structural Annotation Overuse7 hits · 12 pts
SeverityFileLineSnippetContext
LOWserver/managers/MigrationManager.js118 // Step 3: If migration fails, save the failed original and restore the backupCOMMENT
LOW⚡server/utils/scandir.js49 // Step 1: Filter out non-book-media files in root dir (with depth of 0)COMMENT
LOW⚡server/utils/scandir.js54 // Step 2: Separate media files and other filesCOMMENT
LOWserver/utils/scandir.js68 // Step 3: Group media files (or non-media files if includeNonMediaFiles is true) in library itemsCOMMENT
LOWserver/utils/scandir.js102 // Step 4: Add other files into library item groupsCOMMENT
LOWserver/utils/queries/libraryItemsBookFilters.js852 // Step 1: Get the first book of every series that hasnt been started yetCOMMENT
LOWserver/utils/queries/libraryItemsBookFilters.js996 // Step 3: Map books to library itemsCOMMENT
Cross-Language Confusion (JS/TS)1 hit · 5 pts
SeverityFileLineSnippetContext
HIGHserver/libs/libarchive/wasm-module.js149 print(...text) {CODE
AI Slop Vocabulary1 hit · 3 pts
SeverityFileLineSnippetContext
MEDIUMserver/utils/parsers/parseOverdriveMediaMarkers.js112 // this allows us to leverage the individual track durations when calculating the start times of chapters in trackCOMMENT
Overly Generic Function Names2 hits · 2 pts
SeverityFileLineSnippetContext
LOWserver/libs/libarchive/wasm-libarchive.js11 var Module = typeof libarchive !== "undefined" ? libarchive : {}; var moduleOverrides = {}; var key; for (key in MCODE
LOWclient/static/libarchive/wasm-gen/libarchive.js8 var Module = typeof libarchive !== "undefined" ? libarchive : {}; var moduleOverrides = {}; var key; for (key in MCODE