AI Slop Code Risk Monitor

permissionlesstech/bitchat

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

bluetooth mesh chat, IRC vibes

2.9 Low pattern signal View on GitHub

Open-Source Code Quality, Security and Technical Debt Review

This report summarizes scanner evidence for permissionlesstech/bitchat, a Swift project with 37,023 GitHub stars. SynthScan examined 170,836 lines of code across 614 source files, recording 429 pattern matches distributed across 6 syntactic categories. The legacy adjusted pattern signal is 2.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.

2.9
Adjusted Signal
2.9
Raw Pattern Score
100%
Time Factor
2026-10-29
Last Push
37.0K
Stars
Swift
Language
170.8K
Lines of Code
614
Files
429
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 13.4/100 · LOW

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

Hallucinated Dependency & Supply Chain Risk 0.2/100 · LOW

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

Agent Over-Engineering Ratio 0.7/100 · LOW

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

PR Review Velocity Impact 13.0/100 · LOW

Which changes need focused human review? 429 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 0HIGH 0MEDIUM 23LOW 406

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 429 distinct pattern matches across 6 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.

Over-Commented Block380 hits · 380 pts
SeverityFileLineSnippetContext
LOW.periphery.yml1# Periphery dead-code scan configuration (https://github.com/peripheryapp/periphery)COMMENT
LOWbitchat/ViewModels/ChatLiveVoiceCoordinator.swift681COMMENT
LOWbitchat/ViewModels/ChatOutgoingCoordinator.swift41 /// coordinator never reads it.)COMMENT
LOW…at/ViewModels/ChatPrivateConversationCoordinator.swift1import BitFoundationCOMMENT
LOW…at/ViewModels/ChatPrivateConversationCoordinator.swift101 /// errors about a DM belong in that DM, not on the active timeline.COMMENT
LOWbitchat/ViewModels/ChatViewModel.swift1//COMMENT
LOWbitchat/ViewModels/ChatViewModel.swift21/// - Command processingCOMMENT
LOWbitchat/ViewModels/ChatViewModel.swift41/// - Supports verified fingerprints for secure communicationCOMMENT
LOWbitchat/ViewModels/ChatViewModel.swift61/// - SwiftUI automatically optimizes UI updatesCOMMENT
LOWbitchat/ViewModels/ChatViewModel.swift221COMMENT
LOWbitchat/ViewModels/ChatViewModel.swift601 /// Note: when this runs after a store `migrateConversation`, the store hasCOMMENT
LOWbitchat/ViewModels/ChatViewModel.swift1701COMMENT
LOWbitchat/ViewModels/NostrInboundPipeline.swift21 func displayNameForNostrPubkey(_ pubkeyHex: String) -> StringCOMMENT
LOWbitchat/ViewModels/NostrInboundPipeline.swift81 @discardableResultCOMMENT
LOWbitchat/ViewModels/NostrInboundPipeline.swift341 }COMMENT
LOWbitchat/ViewModels/PublicMessagePipeline.swift1//COMMENT
LOWbitchat/ViewModels/GeoChannelCoordinator.swift1//COMMENT
LOWbitchat/ViewModels/ChatPeerIdentityCoordinator.swift1import BitFoundationCOMMENT
LOWbitchat/ViewModels/ChatPeerIdentityCoordinator.swift101 func sendFavoriteNotificationViaNostr(noisePublicKey: Data, isFavorite: Bool)COMMENT
LOWbitchat/ViewModels/ChatGroupCoordinator.swift521COMMENT
LOWbitchat/ViewModels/ChatMediaTransferCoordinator.swift141}COMMENT
LOWbitchat/ViewModels/ChatNostrCoordinator.swift21 func sendGeohashDeliveryAck(for messageID: String, toRecipientHex recipientHex: String, from identity: NostrIdentityCOMMENT
LOW…hat/ViewModels/ChatPublicConversationCoordinator.swift1import BitFoundationCOMMENT
LOW…hat/ViewModels/ChatPublicConversationCoordinator.swift101extension ChatViewModel: ChatPublicConversationContext {COMMENT
LOW…hat/ViewModels/ChatPublicConversationCoordinator.swift421 /// rate limit; low/no-PoW events keep the strict limits so old clientsCOMMENT
LOWbitchat/ViewModels/ChatVerificationCoordinator.swift61 func privateMediaPeerDidAuthenticate(_ peerID: PeerID)COMMENT
LOWbitchat/ViewModels/ChatLifecycleCoordinator.swift61COMMENT
LOWbitchat/ViewModels/ChatTransportEventCoordinator.swift81 func handleVoiceFramePayload(from peerID: PeerID, payload: Data, timestamp: Date)COMMENT
LOWbitchat/ViewModels/ChatViewModelBootstrapper.swift221 /// mesh messages, persisted across restarts) as dimmed "heard hereCOMMENT
LOWbitchat/ViewModels/ChatDeliveryCoordinator.swift1import BitFoundationCOMMENT
LOWbitchat/ViewModels/ChatDeliveryCoordinator.swift41 func notifyUIChanged()COMMENT
LOWbitchat/ViewModels/ChatPeerListCoordinator.swift1import BitFoundationCOMMENT
LOWbitchat/App/AppRuntime.swift461COMMENT
LOWbitchat/App/NearbyNotesCounter.swift1//COMMENT
LOWbitchat/App/PrivacyScreen.swift1//COMMENT
LOWbitchat/App/ConversationStore.swift1//COMMENT
LOWbitchat/App/ConversationStore.swift341 // MARK: Selection stateCOMMENT
LOWbitchat/App/ConversationStore.swift361 /// message into both the stable-key and ephemeral-peer chatsCOMMENT
LOWbitchat/App/ConversationStore.swift441 /// republish and `.statusChanged` event - otherwise a view observing theCOMMENT
LOWbitchat/App/ConversationStore.swift701COMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift1//COMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift21/// - Thread-safe access patternsCOMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift41/// - No cloud sync or backupCOMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift61///COMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift81/// - Users can disable all persistenceCOMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift161 // In-memory stateCOMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift181 // `.profraw`, deadlocking the process at teardown on the constrained CICOMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift241 if !keyIsEphemeral {COMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift321 }COMMENT
LOWbitchat/Identity/SecureIdentityStateManager.swift361 /// TOFU signing-key pinning: once a signing key has been persisted for aCOMMENT
LOWbitchat/Identity/IdentityModels.swift1//COMMENT
LOWbitchat/Identity/IdentityModels.swift21/// The layers are separate concerns, but they are not independent: the networkCOMMENT
LOWbitchat/Identity/IdentityModels.swift41///COMMENT
LOWbitchat/Identity/IdentityModels.swift61/// 2. **Casual**: Basic interaction historyCOMMENT
LOWbitchat/Identity/IdentityModels.swift81/// // When peer connects with new IDCOMMENT
LOWbitchat/Identity/IdentityModels.swift141/// `vouched` mid-ladder cannot corrupt previously persisted values — everyCOMMENT
LOWbitchat/Identity/IdentityModels.swift201 // Fingerprint -> when we verified it (orders outgoing vouch batches;COMMENT
LOWbitchat/Features/voice/PTTBurstPlayer.swift1//COMMENT
LOWbitchat/Features/voice/PTTBurstPlayer.swift141 }COMMENT
LOWbitchat/Features/voice/VoiceCaptureSession.swift1//COMMENT
320 more matches not shown…
AI Slop Vocabulary22 hits · 84 pts
SeverityFileLineSnippetContext
MEDIUMbitchat/Services/BLE/BLEAnnounceHandler.swift248 // Persist cryptographic identity and signing key for robust offlineCOMMENT
MEDIUM…tFoundation/Sources/BitFoundation/BinaryProtocol.swift258 // Try decode as-is first (robust when padding wasn't applied)COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift81 #expect(harness.lines.isEmpty)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift94 #expect(harness.lines.isEmpty)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift103 #expect(harness.lines.isEmpty)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift106 #expect(harness.lines.count == 1)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift107 #expect(harness.lines[0].geohash == "9q8yy")COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift108 #expect(harness.lines[0].content.contains("road closed"))COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift109 #expect(harness.lines[0].content.contains("@alice"))COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift122 #expect(harness.lines.isEmpty)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift135 #expect(harness.lines.count == 1)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift136 #expect(harness.lines[0].content.contains("3"))COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift137 #expect(harness.pendingFlushes.isEmpty)COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift149 #expect(harness.lines.count == 2)COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift150 #expect(Set(harness.lines.map(\.geohash)) == ["9q8yy", ""])COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift164 #expect(harness.lines.count == 1)COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift165 #expect(!harness.lines[0].content.contains("2"))COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift192 #expect(harness.pendingFlushes.count == 1)COMMENT
MEDIUMbitchatTests/Services/BoardAlertsModelTests.swift198 #expect(harness.lines.isEmpty)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift211 #expect(harness.lines.count == 1)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift212 #expect(harness.lines[0].content.count < 200)COMMENT
MEDIUM⚡bitchatTests/Services/BoardAlertsModelTests.swift213 #expect(harness.lines[0].content.contains("…"))COMMENT
Hyper-Verbose Identifiers20 hits · 24 pts
SeverityFileLineSnippetContext
LOWscripts/tests/test_fetch_georelays_workflow.py15 def test_write_capable_checkout_action_is_immutable(self) -> None:CODE
LOWscripts/tests/test_fetch_georelays_workflow.py21 def test_pr_failure_has_single_issue_fallback_with_review_metadata(self) -> None:CODE
LOWscripts/tests/test_fetch_georelays_workflow.py45 def test_obsolete_review_state_is_cleaned_without_pushing_main(self) -> None:CODE
LOWscripts/tests/test_fetch_georelays_workflow.py53 def test_workflow_runs_all_validator_tests(self) -> None:CODE
LOWscripts/tests/test_validate_georelays.py15 def test_validates_and_deduplicates_secure_relay_addresses(self) -> None:CODE
LOWscripts/tests/test_validate_georelays.py29 def test_rejects_insecure_or_non_host_relay_urls(self) -> None:CODE
LOWscripts/tests/test_validate_georelays.py53 def test_rejects_malformed_rows_and_unsafe_coordinates(self) -> None:CODE
LOWscripts/tests/test_validate_georelays.py71 def test_accepts_ascii_coordinate_forms_supported_by_swift_double(self) -> None:CODE
LOWscripts/tests/test_validate_georelays.py85 def test_rejects_conflicts_limits_and_large_baseline_deltas(self) -> None:CODE
LOWscripts/tests/test_validate_georelays.py117 def test_update_requires_exact_normalized_baseline_entry_overlap(self) -> None:CODE
LOWscripts/tests/test_validate_georelays.py157 def test_cli_copies_only_validated_data_and_emits_review_metadata(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py33 def test_runs_on_untrusted_pull_request_trigger(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py38 def test_no_job_holds_a_write_scope(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py43 def test_checkout_does_not_persist_credentials(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py46 def test_relay_data_changes_trigger_the_workflow(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py52 def test_gate_checks_out_the_reviewed_base(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py57 def test_gate_runs_nothing_the_pull_request_wrote(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py66 def test_gate_pins_both_inputs_to_the_event(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py74 def test_gate_validation_cannot_write_to_the_reviewed_file(self) -> None:CODE
LOW⚡scripts/tests/test_georelay_pr_workflow.py79 def test_proposed_validator_is_exercised_against_the_real_directory(self) -> None:CODE
Fake / Example Data5 hits · 6 pts
SeverityFileLineSnippetContext
LOWbitchat/_PreviewHelpers/BitchatMessage+Preview.swift16 sender: "John Doe",CODE
LOWbitchat/_PreviewHelpers/BitchatMessage+Preview.swift22 recipientNickname: "Jane Doe",CODE
LOWbitchat/Views/Components/DeliveryStatusView.swift141 .delivered(to: "John Doe", at: Date()),CODE
LOWbitchat/Views/Components/DeliveryStatusView.swift142 .read(by: "Jane Doe", at: Date()),CODE
LOWbitchatTests/ProtocolContractTests.swift107 #expect(preview.sender == "John Doe")COMMENT
Modern AI Meta-Vocabulary1 hit · 3 pts
SeverityFileLineSnippetContext
MEDIUMbitchat/Services/VerificationService.swift120 // MARK: - Noise payloads (scaffold only)COMMENT
Unused Imports1 hit · 1 pts
SeverityFileLineSnippetContext
LOWscripts/validate_georelays.py4CODE