Readest is a modern, feature-rich ebook reader designed for avid readers offering seamless cross-platform access, powerful tools, and an intuitive interface to elevate your reading experience.
This report presents the forensic synthetic code analysis of readest/readest, a TypeScript project with 22,335 GitHub stars. SynthScan v2.0 examined 450,237 lines of code across 2322 source files, recording 556 pattern matches distributed across 14 syntactic categories. The overall adjusted score of 2.3 places this repository in the Likely human-written band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
This chart maps the temporal evolution of the adjusted synthetic code score across successive scan runs. An upward trajectory indicates ongoing incorporation of AI-generated code or expanding LLM-assisted scaffolding; a stable or declining trajectory may reflect active human refactoring, code removal, or the adoption of stricter authorship policies. The dashed secondary line (right axis) independently tracks total raw pattern hit count, which can diverge from the normalised score when codebase size changes significantly between scans.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 556 distinct pattern matches across 14 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. 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 diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | .github/workflows/nightly.yml | 175 | # ──────────────────────────── ANDROID ──────────────────────────── | COMMENT |
| MEDIUM | .github/workflows/nightly.yml | 215 | # ──────────────────────────── DESKTOP ──────────────────────────── | COMMENT |
| MEDIUM | .github/workflows/nightly.yml | 321 | # ───────────────── COLLECT ARTIFACTS + BUILD FRAGMENT ───────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 24 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 26 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 113 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 115 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 243 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 245 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 274 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 276 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 337 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 339 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 362 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 364 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 379 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 381 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 466 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 468 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 528 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …est-app/extensions/windows-thumbnail/src/extraction.rs | 530 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 38 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 40 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 74 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 76 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 113 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 115 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 268 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 270 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 325 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 327 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 383 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …t-app/extensions/windows-thumbnail/src/com_provider.rs | 385 | // ───────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 1249 | // ── Sync passphrase keychain ────────────────────────────────────────── | COMMENT |
| MEDIUM | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 1327 | // ── Keyed secure key-value store ────────────────────────────────── | COMMENT |
| MEDIUM | …ive-bridge/android/src/main/java/NativeBridgePlugin.kt | 1136 | // ── Sync passphrase keychain ────────────────────────────────────── | COMMENT |
| MEDIUM | …ive-bridge/android/src/main/java/NativeBridgePlugin.kt | 1221 | // ── Keyed secure key-value store ────────────────────────────────── | COMMENT |
| MEDIUM | …tauri/plugins/tauri-plugin-native-bridge/src/models.rs | 292 | // ── Sync passphrase keychain ──────────────────────────────────────────── | COMMENT |
| MEDIUM | …tauri/plugins/tauri-plugin-native-bridge/src/models.rs | 362 | // ── Keyed secure key-value store ───────────────────────────────────────── | COMMENT |
| MEDIUM | …auri/plugins/tauri-plugin-native-bridge/src/desktop.rs | 203 | // ── Sync passphrase keychain ──────────────────────────────────────── | COMMENT |
| MEDIUM | …auri/plugins/tauri-plugin-native-bridge/src/desktop.rs | 289 | // ── Keyed secure key-value store ──────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src-tauri/gen/apple/project.yml | 36 | # ---------------------------------- | COMMENT |
| MEDIUM | …est-app/src/app/reader/components/rsvp/RSVPControl.tsx | 39 | // ─── TTS-sync decision logic (slice 5, #3235) ────────────────────────── | COMMENT |
| MEDIUM | …est-app/src/app/reader/components/rsvp/RSVPControl.tsx | 39 | // ─── TTS-sync decision logic (slice 5, #3235) ────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/tauriEpubBridge.ts | 38 | // ─── shared helpers ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/tauriEpubBridge.ts | 55 | // ─── parse_epub_metadata (import path) ─────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/tauriEpubBridge.ts | 177 | // ─── parse_epub_full (open hot-path prefetch) ──────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/bridge.ts | 282 | // ── Sync passphrase keychain ──────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/bridge.ts | 327 | // ── Keyed secure key-value store ───────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/bridge.ts | 368 | // ── Reading widget ──────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/bridge.ts | 394 | // ── Nightly updater (main-app commands, no native-bridge prefix) ───────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/tauriMobiBridge.ts | 42 | // ─── shared helpers ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/tauriMobiBridge.ts | 70 | // ─── parse_mobi_metadata (import path) ─────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/warichu.ts | 120 | // ── Core measurement ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/warichu.ts | 173 | // ── Build nodes ─────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/warichu.ts | 356 | // ── Helpers ─────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/warichu.ts | 472 | // ── HTML slicing helpers ────────────────────────────────────────────── | COMMENT |
| MEDIUM | apps/readest-app/src/utils/event.ts | 71 | // ─── Settled events (one-shot, replay-on-subscribe) ──────────────────── | COMMENT |
| MEDIUM | …p/src/__tests__/tauri/epub-parser-parity.tauri.test.ts | 39 | // ─── Rust IPC return shapes (serde camelCase) ──────────────────────── | COMMENT |
| MEDIUM | …p/src/__tests__/tauri/epub-parser-parity.tauri.test.ts | 60 | // ─── helpers ───────────────────────────────────────────────────────── | COMMENT |
| 145 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | Cargo.toml | 41 | tauri = { path = "packages/tauri/crates/tauri" } | COMMENT |
| LOW | packages/swift-rs/src-rs/dark_magic.rs | 1 | /// This retain-balancing algorithm is cool but likely isn't required. | COMMENT |
| LOW | packages/swift-rs/src-rs/dark_magic.rs | 21 | // }); | COMMENT |
| LOW | packages/swift-rs/src-rs/dark_magic.rs | 41 | COMMENT | |
| LOW | packages/swift-rs/src-rs/dark_magic.rs | 61 | COMMENT | |
| LOW | packages/swift-rs/src-rs/dark_magic.rs | 81 | // retain_object(ptr) | COMMENT |
| LOW | packages/swift-rs/src-rs/build.rs | 261 | command | COMMENT |
| LOW | packages/swift-rs/src-rs/swift_arg.rs | 1 | use std::ffi::c_void; | COMMENT |
| LOW | packages/swift-rs/src-rs/autorelease.rs | 1 | /// Run code with its own autorelease pool. Semantically, this is identical | COMMENT |
| LOW | packages/swift-rs/src-rs/swift.rs | 21 | fn get_object(&self) -> &SRObject<Self::Shape>; | COMMENT |
| LOW | packages/swift-rs/src-rs/swift.rs | 61 | /// | COMMENT |
| LOW | packages/swift-rs/src-rs/types/object.rs | 1 | use crate::swift::{self, SwiftObject}; | COMMENT |
| LOW | packages/swift-rs/src-rs/types/object.rs | 21 | /// struct CustomObject { | COMMENT |
| LOW | packages/swift-rs/src-rs/types/array.rs | 21 | /// ## Returning Directly | COMMENT |
| LOW | packages/swift-rs/src-rs/types/array.rs | 41 | /// | COMMENT |
| LOW | .github/workflows/codeql.yml | 1 | # For most projects, this workflow file will not need changing; you simply need | COMMENT |
| LOW | .github/workflows/scorecard.yml | 41 | - name: "Run analysis" | COMMENT |
| LOW | apps/readest-app/vitest.tauri.setup.ts | 1 | // Vitest runs tests inside an iframe, but Tauri injects its plugin internals | COMMENT |
| LOW | apps/readest-app/scripts/sync-release-notes.sh | 1 | #!/bin/bash | COMMENT |
| LOW | …eadest-app/scripts/verify-ios-appstore-entitlements.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | apps/readest-app/scripts/worktree-new.ts | 241 | } | COMMENT |
| LOW | apps/readest-app/src-tauri/Cargo.toml | 81 | # href is percent-encoded (e.g. spaces as %20, CJK paths) but the zip stores | COMMENT |
| LOW | apps/readest-app/src-tauri/Cargo.toml | 101 | COMMENT | |
| LOW | …ri-plugin-native-tts/ios/Sources/NativeTTSPlugin.swift | 121 | // Remote command targets we registered. The lock-screen command center | COMMENT |
| LOW | …ri-plugin-native-tts/ios/Sources/NativeTTSPlugin.swift | 141 | private var lastSessionOpTime = Date.distantPast | COMMENT |
| LOW | …ri-plugin-native-tts/ios/Sources/NativeTTSPlugin.swift | 181 | // iOS runtime — and it is the ONLY lever that flips the client's playback | COMMENT |
| LOW | …tive-tts/android/src/main/java/MediaPlaybackService.kt | 241 | // Deliver metadata/state updates to the live service in-process rather | COMMENT |
| LOW | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 521 | // leaving the system stuck at the app's level until the user nudges it | COMMENT |
| LOW | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 621 | /// Bridge between the Readest Share Extension (separate process) and | COMMENT |
| LOW | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 1401 | // Bridge for the system-dictionary "Look Up" surface on iOS. | COMMENT |
| LOW | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 1441 | // dictionary availability, but the static | COMMENT |
| LOW | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 1521 | } | COMMENT |
| LOW | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 1661 | /// and stash the bytes in `UserDefaults` keyed by the POSIX path. | COMMENT |
| LOW | …gin-native-bridge/ios/Sources/NativeBridgePlugin.swift | 1781 | /// picker invocations would each hold their own state — currently we | COMMENT |
| LOW | …ugin-native-bridge/ios/Sources/ClipUrlController.swift | 41 | case .loadFailed(let detail): return "Could not fetch this page: \(detail)" | COMMENT |
| LOW | …-native-bridge/ios/Sources/ContextMenuSuppressor.swift | 1 | import ObjectiveC | COMMENT |
| LOW | …-native-bridge/ios/Sources/ContextMenuSuppressor.swift | 21 | /// a backstop in case WebKit presents without re-querying the delegate. | COMMENT |
| LOW | …ive-bridge/android/src/main/java/NativeBridgePlugin.kt | 321 | // shared-intent events emitted before the JS side has registered its | COMMENT |
| LOW | …tauri/plugins/tauri-plugin-native-bridge/src/models.rs | 241 | pub struct OpenExternalUrlResponse { | COMMENT |
| LOW | …tauri/plugins/tauri-plugin-native-bridge/src/models.rs | 321 | /// Args for the mobile URL-clip flow. Mirrors the public `ClipOptions` | COMMENT |
| LOW | …tauri/plugins/tauri-plugin-native-bridge/src/models.rs | 361 | COMMENT | |
| LOW | …auri/plugins/tauri-plugin-native-bridge/src/desktop.rs | 201 | } | COMMENT |
| LOW | apps/readest-app/src-tauri/gen/apple/project.yml | 41 | # DEVELOPMENT_TEAM is set; inherits IAP from the App ID. | COMMENT |
| LOW | apps/readest-app/src-tauri/gen/apple/project.yml | 161 | # may overwrite the file (even with no properties declared) during | COMMENT |
| LOW | …rc-tauri/gen/apple/ShareExtension/AppGroupBridge.swift | 1 | // Shared App Group container schema between the Readest Share Extension and | COMMENT |
| LOW | …uri/gen/apple/ShareExtension/ShareViewController.swift | 1 | // Share Extension for Readest: catches an article URL from any iOS share | COMMENT |
| LOW | …uri/gen/apple/ShareExtension/ShareViewController.swift | 21 | // | COMMENT |
| LOW | apps/readest-app/src-tauri/src/spawn_fresh_browser.rs | 1 | //! Open a URL in a freshly-spawned, isolated browser process. | COMMENT |
| LOW | apps/readest-app/src-tauri/src/spawn_fresh_browser.rs | 21 | //! | COMMENT |
| LOW | apps/readest-app/src-tauri/src/lib.rs | 81 | log::error!("Failed to allow directory in asset_protocol_scope: {e}"); | COMMENT |
| LOW | apps/readest-app/src-tauri/src/lib.rs | 101 | /// - On desktop, this command refuses to extend `asset_protocol_scope` | COMMENT |
| LOW | apps/readest-app/src-tauri/src/lib.rs | 121 | /// can only read paths for which it holds a security-scoped | COMMENT |
| LOW | apps/readest-app/src-tauri/src/lib.rs | 281 | #[cfg(not(target_os = "linux"))] | COMMENT |
| LOW | apps/readest-app/src-tauri/src/clip_url.rs | 1 | // Spawn a hidden Tauri webview that loads the target URL with the real | COMMENT |
| LOW | apps/readest-app/src-tauri/src/clip_url.rs | 21 | // invoke('clip_url', url) ─┬─▶ bind 127.0.0.1:RANDOM_PORT | COMMENT |
| LOW | apps/readest-app/src-tauri/src/clip_url.rs | 541 | window.__readest_setStatus__(CAPTURING_STATUS); | COMMENT |
| LOW | apps/readest-app/src-tauri/src/clip_url.rs | 581 | // Hard fallback in case `load` never fires (SPA, error state, | COMMENT |
| LOW | apps/readest-app/src-tauri/src/clip_url.rs | 661 | } | COMMENT |
| LOW | apps/readest-app/src-tauri/src/mobi_parser.rs | 1 | // Native MOBI/AZW/AZW3 import path. | COMMENT |
| LOW | apps/readest-app/src-tauri/src/mobi_parser.rs | 21 | // - locate the cover image (EXTH `CoverOffset` 201 → `ThumbOffset` 202 | COMMENT |
| 140 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …p/.claude/plans/2026-06-18-sync-reading-status-plan.md | 513 | export function resolveReadingStatusMerge( | CODE |
| LOW | …ers/plans/2026-05-30-tts-highlight-current-sentence.md | 148 | export function buildTTSSentenceHighlight( | CODE |
| LOW | …cs/2026-05-30-tts-highlight-current-sentence-design.md | 167 | export function buildTTSSentenceHighlight( | CODE |
| LOW | …extensions/send-to-readest/src/background/offscreen.ts | 119 | export async function clipAndUploadViaOffscreen(opts: { | CODE |
| LOW | …/readest-app/src/app/reader/utils/globalAnnotations.ts | 304 | export function expandAllRenderedSections(view: FoliateView | null, note: BookNote): void { | CODE |
| LOW | …/readest-app/src/app/reader/utils/globalAnnotations.ts | 343 | export function removeGlobalAnnotationOverlays( | CODE |
| LOW | apps/readest-app/src/app/reader/utils/annotatorUtil.ts | 145 | export function getHandlePositionsFromRange( | CODE |
| LOW | apps/readest-app/src/app/reader/utils/annotatorUtil.ts | 277 | export function removeEmptyAnnotationPlaceholder( | CODE |
| LOW | apps/readest-app/src/app/reader/utils/annotatorUtil.ts | 305 | export function buildTTSSentenceHighlight( | CODE |
| LOW | …ps/readest-app/src/app/reader/utils/annotationIndex.ts | 61 | export function selectLocationAnnotations( | CODE |
| LOW | …app/src/app/reader/components/notebook/AIAssistant.tsx | 41 | function convertToExportedMessages( | CODE |
| LOW | …adest-app/src/app/reader/hooks/useAutoSaveBookCover.ts | 102 | async function tryWriteFullCoverFromBook( | CODE |
| LOW | apps/readest-app/src/app/api/stripe/webhook/route.ts | 84 | async function handleSuccessfulSubscription(session: Stripe.Checkout.Session, userId: string) { | CODE |
| LOW | apps/readest-app/src/app/api/stripe/webhook/route.ts | 162 | async function handleSubscriptionUpdated(subscription: Stripe.Subscription) { | CODE |
| LOW | apps/readest-app/src/app/api/stripe/webhook/route.ts | 180 | async function handleSubscriptionCancelled(subscription: Stripe.Subscription) { | CODE |
| LOW | apps/readest-app/src/libs/payment/iap/apple/server.ts | 30 | export async function createOrUpdateSubscription(userId: string, purchase: VerifiedPurchase) { | CODE |
| LOW | …adest-app/src/libs/payment/iap/google/notifications.ts | 108 | async function handleSubscriptionNotification( | CODE |
| LOW | apps/readest-app/src/libs/payment/iap/google/server.ts | 40 | export async function createOrUpdateSubscription(userId: string, purchase: VerifiedPurchase) { | CODE |
| LOW | …-app/src/__tests__/hooks/useSpatialNavigation.test.tsx | 56 | function simulateKeyboardActivation() { | CODE |
| LOW | apps/readest-app/src/hooks/usePullToRefresh.ts | 104 | function updateLoadingSpinnerPosition(el: HTMLDivElement, transform: number, dy: number) { | CODE |
| LOW | apps/readest-app/src/pages/api/sync.ts | 60 | export function resolveReadingStatusMerge( | CODE |
| LOW | apps/readest-app/src/pages/api/sync.ts | 87 | export function buildStatusPropagationRow( | CODE |
| LOW | apps/readest-app/src/services/cloudService.ts | 134 | export async function downloadReplicaFileFromCloud( | CODE |
| LOW | apps/readest-app/src/services/cloudService.ts | 153 | export async function deleteReplicaBundleFromCloud( | CODE |
| LOW | apps/readest-app/src/services/bookService.ts | 85 | export function normalizeFilePathForIndex(path: string, osPlatform?: OsPlatform): string { | CODE |
| LOW | apps/readest-app/src/services/bookService.ts | 723 | export async function resolveNativeBookFilePath( | CODE |
| LOW | apps/readest-app/src/services/backupService.ts | 113 | export function sanitizeSettingsForBackup( | CODE |
| LOW | apps/readest-app/src/services/bookContent.ts | 28 | async function resolveLegacyManagedSource( | CODE |
| LOW | apps/readest-app/src/services/settingsService.ts | 64 | export function migrateHighlightColorPrefs(read: ReadSettings): void { | CODE |
| LOW | …adest-app/src/services/translators/providers/yandex.ts | 10 | async function translateSingleTextForService( | CODE |
| LOW | …p/src/services/reedy/tools/builtins/createHighlight.ts | 26 | export function createCreateHighlightTool( | CODE |
| LOW | …src/services/reedy/tools/builtins/getReadingContext.ts | 14 | export function createGetReadingContextTool( | CODE |
| LOW⚡ | …t-app/src/services/reedy/tools/builtins/memoryTools.ts | 135 | export function createSearchUserMemoryTool(deps: SearchMemoryToolDeps) { | CODE |
| LOW⚡ | …t-app/src/services/reedy/tools/builtins/memoryTools.ts | 144 | export function createWriteUserMemoryTool(deps: WriteMemoryToolDeps) { | CODE |
| LOW⚡ | …t-app/src/services/reedy/tools/builtins/memoryTools.ts | 153 | export function createSearchBookMemoryTool(deps: SearchMemoryToolDeps) { | CODE |
| LOW⚡ | …t-app/src/services/reedy/tools/builtins/memoryTools.ts | 162 | export function createWriteBookMemoryTool(deps: WriteMemoryToolDeps) { | CODE |
| LOW⚡ | …t-app/src/services/reedy/tools/builtins/memoryTools.ts | 171 | export function createSearchSessionMemoryTool(deps: SearchMemoryToolDeps) { | CODE |
| LOW | …p/src/services/ai/providers/ProxiedGatewayEmbedding.ts | 8 | export function createProxiedEmbeddingModel(options: ProxiedEmbeddingOptions): EmbeddingModel { | CODE |
| LOW | …s/readest-app/src/services/ai/adapters/ReedyBackend.ts | 162 | function mapToolEventToMetricEvent( | CODE |
| LOW | apps/readest-app/src/store/proofreadStore.ts | 370 | export function validateReplacementRulePattern( | CODE |
| LOW | apps/readest-calibre-plugin/tests/test_hashes.py | 40 | def test_small_file_reads_everything(self): | CODE |
| LOW | apps/readest-calibre-plugin/tests/test_hashes.py | 50 | def test_skips_middle_of_larger_file(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_hashes.py | 82 | def test_prefers_uuid_over_isbn(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_hashes.py | 88 | def test_calibre_scheme_preferred_over_isbn(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_hashes.py | 94 | def test_urn_identifier_sliced_after_last_colon(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_hashes.py | 103 | def test_plain_identifier_without_scheme(self): | CODE |
| LOW | apps/readest-calibre-plugin/tests/test_wire.py | 110 | def test_single_author_is_string(self): | CODE |
| LOW | apps/readest-calibre-plugin/tests/test_wire.py | 122 | def test_strips_nul_characters(self): | CODE |
| LOW | apps/readest-calibre-plugin/tests/test_wire.py | 143 | def test_meta_hash_uses_uuid_identifier(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 170 | def test_new_book_without_cover(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 175 | def test_unchanged_book_is_skipped(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 180 | def test_changed_metadata_is_update(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 187 | def test_changed_cover_only_is_update_with_cover(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 193 | def test_tombstoned_row_is_resurrected(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 200 | def test_tags_change_is_update(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 205 | def test_missing_local_cover_does_not_force_update(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 210 | def test_row_without_file_is_replaced(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 218 | def test_changed_source_file_is_replaced(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 251 | def test_index_prefers_live_row(self): | CODE |
| LOW⚡ | apps/readest-calibre-plugin/tests/test_wire.py | 261 | def test_index_prefers_newer_row(self): | CODE |
| 13 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | packages/swift-rs/README.md | 226 | else return SRString("lorem ipsum") | CODE |
| LOW | packages/swift-rs/README.md | 272 | let value: SRString = "lorem ipsum".into(); | CODE |
| LOW | packages/swift-rs/README.md | 274 | unsafe { swift_print(&value) }; // Will print "lorem ipsum" to the console | CODE |
| LOW | packages/swift-rs/README.md | 285 | let value = "lorem ipsum" | CODE |
| LOW | packages/swift-rs/README.md | 306 | println!("{}", value_srstring); // Will print "lorem ipsum" to the console | CODE |
| LOW | …s/readest-app/src/app/library/components/GroupItem.tsx | 218 | <div className='placeholder' style={{ height: `${iconSize15}px` }}></div> | CODE |
| LOW | apps/readest-app/src/styles/globals.css | 525 | [data-eink='true'] [class*='placeholder']::placeholder { | CODE |
| LOW | apps/readest-app/src/__tests__/reedy/CfiChunker.test.ts | 112 | const paragraph = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(40); | CODE |
| LOW | apps/readest-app/src/__tests__/reedy/CfiChunker.test.ts | 112 | const paragraph = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(40); | CODE |
| LOW | …st-app/src/__tests__/app/library/group-header.test.tsx | 56 | render(<GroupHeader groupBy={LibraryGroupByType.Author} groupName='Jane Doe' />); | CODE |
| LOW | apps/readest-app/src/__tests__/utils/md.test.ts | 132 | expect(fm.metadata.author).toBe('Jane Doe'); | CODE |
| LOW⚡ | …/readest-app/src/__tests__/utils/library-utils.test.ts | 44 | expect(parseAuthors('John Smith, Jane Doe')).toEqual(['John Smith', 'Jane Doe']); | CODE |
| LOW⚡ | …/readest-app/src/__tests__/utils/library-utils.test.ts | 48 | expect(parseAuthors('John Smith & Jane Doe')).toEqual(['John Smith', 'Jane Doe']); | CODE |
| LOW⚡ | …/readest-app/src/__tests__/utils/library-utils.test.ts | 52 | expect(parseAuthors('John Smith and Jane Doe')).toEqual(['John Smith', 'Jane Doe']); | CODE |
| LOW⚡ | …/readest-app/src/__tests__/utils/library-utils.test.ts | 58 | 'Jane Doe', | CODE |
| LOW⚡ | …/readest-app/src/__tests__/utils/library-utils.test.ts | 66 | 'Jane Doe', | CODE |
| LOW⚡ | …/readest-app/src/__tests__/utils/library-utils.test.ts | 72 | expect(parseAuthors(' John Smith , Jane Doe ')).toEqual(['John Smith', 'Jane Doe']); | CODE |
| LOW | …/readest-app/src/__tests__/utils/library-utils.test.ts | 216 | const jane = groups.find((g) => g.name === 'Jane Doe'); | CODE |
| LOW | apps/readest-app/src/__tests__/utils/txt-worker.test.ts | 55 | const options = { file, author: 'Jane Doe', language: 'zh' }; | CODE |
| LOW | …adest-app/src/__tests__/libs/replicaSyncClient.test.ts | 4 | getAccessToken: vi.fn(async () => 'fake-token'), | CODE |
| LOW | …adest-app/src/__tests__/libs/replicaSyncClient.test.ts | 51 | expect(init.headers.Authorization).toBe('Bearer fake-token'); | CODE |
| LOW | apps/readest-app/src/__tests__/ai/chunker.test.ts | 67 | const longText = 'Lorem ipsum dolor sit amet. '.repeat(50); | CODE |
| LOW | apps/readest-app/src/__tests__/ai/chunker.test.ts | 67 | const longText = 'Lorem ipsum dolor sit amet. '.repeat(50); | CODE |
| LOW | …c/__tests__/services/send-convert-page-unified.test.ts | 41 | <p>${'lorem ipsum dolor sit amet '.repeat(40)}</p> | CODE |
| LOW | …c/__tests__/services/send-convert-page-unified.test.ts | 41 | <p>${'lorem ipsum dolor sit amet '.repeat(40)}</p> | CODE |
| LOW | …eadest-app/src/__tests__/services/send-address.test.ts | 20 | expect(slugFromIdentity('Jane Doe')).toBe('janedoe'); | CODE |
| LOW | …pp/src/__tests__/services/send-cover-generator.test.ts | 43 | author: 'Jane Doe', | CODE |
| LOW | …pp/src/__tests__/services/send-cover-generator.test.ts | 46 | expect(svg).toContain('Jane Doe'); | CODE |
| LOW⚡ | …pp/src/__tests__/services/send-cover-generator.test.ts | 126 | expect(pickTheme('Jane Doe')).toEqual(pickTheme('Jane Doe')); | CODE |
| LOW⚡ | …pp/src/__tests__/services/send-cover-generator.test.ts | 131 | const theme = pickTheme('Jane Doe'); | CODE |
| LOW⚡ | …pp/src/__tests__/services/send-cover-generator.test.ts | 137 | expect(pickTheme(' Jane Doe ')).toEqual(pickTheme('Jane Doe')); | CODE |
| LOW | …p/src/__tests__/services/sync/adapters/texture.test.ts | 12 | id: 'placeholder', | CODE |
| LOW | …-app/src/__tests__/services/sync/adapters/font.test.ts | 12 | id: 'placeholder', | CODE |
| LOW | …rc/__tests__/services/sync/adapters/dictionary.test.ts | 11 | id: 'placeholder', | CODE |
| LOW | …ps/readest.koplugin/spec/library/group_covers_spec.lua | 98 | cloud_covers.set_opts({ sync_auth = "fake-token" }) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | apps/readest-app/scripts/test-tauri.sh | 54 | # exists in this harness run. | COMMENT |
| MEDIUM | …tive-tts/android/src/main/java/MediaPlaybackService.kt | 553 | // Promote with an explicit mediaPlayback type (required/robust on | COMMENT |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| MEDIUM | …ps/readest-app/src/app/reader/hooks/useProgressSync.ts | 249 | // TODO: general config sync via a more robust profile-based solution. | COMMENT |
| MEDIUM | …c/__tests__/services/tts-auto-advance.browser.test.tsx | 541 | // The robust, event-agnostic observable: the section the iterator's CURRENT | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | apps/readest-app/.claude/skills/i18n-koplugin/SKILL.md | 14 | ## Step 1: Determine the working directory | COMMENT |
| LOW | apps/readest-app/.claude/skills/i18n-koplugin/SKILL.md | 18 | ## Step 2: Extract msgids from Lua sources | COMMENT |
| LOW | apps/readest-app/.claude/skills/i18n-koplugin/SKILL.md | 34 | ## Step 3: Find untranslated entries | COMMENT |
| LOW | apps/readest-app/.claude/skills/i18n-koplugin/SKILL.md | 62 | ## Step 4: Translate empty msgstrs | COMMENT |
| LOW | apps/readest-app/.claude/skills/i18n-koplugin/SKILL.md | 98 | ## Step 5: Verify | COMMENT |
| LOW | apps/readest-app/.claude/skills/i18n/SKILL.md | 13 | ## Step 0: Determine the mode | COMMENT |
| LOW | apps/readest-app/.claude/skills/i18n/SKILL.md | 18 | ## Step 1: Determine the working directory | COMMENT |
| LOW⚡ | apps/readest-app/.claude/skills/i18n/SKILL.md | 54 | ### Step 2: Extract i18n strings | COMMENT |
| LOW⚡ | apps/readest-app/.claude/skills/i18n/SKILL.md | 63 | ### Step 3: Find untranslated strings | COMMENT |
| LOW⚡ | apps/readest-app/.claude/skills/i18n/SKILL.md | 71 | ### Step 4: Translate missing strings | COMMENT |
| LOW | apps/readest-app/.claude/skills/i18n/SKILL.md | 90 | ### Step 5: Verify | COMMENT |
| LOW | apps/readest-app/docs/testing.md | 37 | ### Step 1: Start the Tauri App | COMMENT |
| LOW | apps/readest-app/docs/testing.md | 53 | ### Step 2: Run Tests | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | …app/extensions/send-to-readest/src/popup/popup.test.ts | 188 | const clipCall = chromeMock.runtime.sendMessage.mock.calls.find((c) => { | CODE |
| CRITICAL | …_tests__/hooks/useSync-stale-settings-clobber.test.tsx | 162 | const lastSaved = h.storeState.saveSettings.mock.calls.at(-1)![1]; | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | .github/workflows/android-e2e.yml | 86 | # the gradle scaffolding, then restore the tracked customizations | COMMENT |
| MEDIUM | apps/readest-app/docs/architecture.md | 405 | ### 6.3 AI / RAG | COMMENT |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| MEDIUM⚡ | apps/readest-app/data/wordlens/en-fr.json | 1 | {"meta":{"source":"en","target":"fr","license":"CC-BY-SA-3.0","attribution":"Glosses: WikDict (CC-BY-SA-3.0), derived fr | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | apps/readest-calibre-plugin/worker.py | 58 | except Exception: | CODE |
| LOW | apps/readest-calibre-plugin/worker.py | 102 | except Exception: | CODE |
| LOW | apps/readest-calibre-plugin/worker.py | 131 | except Exception as err: | CODE |
| LOW | apps/readest-calibre-plugin/worker.py | 150 | except Exception as err: | CODE |
| LOW | apps/readest-calibre-plugin/worker.py | 178 | except Exception: | CODE |
| MEDIUM | apps/readest-calibre-plugin/worker.py | 123 | def run(self): | CODE |
| LOW | apps/readest-calibre-plugin/api.py | 266 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | .github/workflows/codeql.yml | 60 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | apps/readest-app/scripts/sync-release-notes.sh | 36 | # Check if required commands are available | COMMENT |
| LOW | apps/readest-app/scripts/sync-release-notes.sh | 64 | # Check if releases key exists | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | apps/readest-app/src/app/api/opds/proxy/route.ts | 46 | async function handleRequest(request: NextRequest, method: 'GET' | 'HEAD') { | CODE |
| LOW | apps/readest-app/src/utils/warichu.ts | 367 | function getData(el: HTMLElement) { | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | apps/readest-app/src/services/cloudService.ts | 346 | // some books may not have cover image, so we need to check if the book is downloaded | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | apps/readest-app/src/services/tts/TTSController.ts | 182 | // TODO: implement native TTS client for desktop platforms. | COMMENT |