AI Slop Code Risk Monitor

chenglou/pretext

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

Fast, accurate & comprehensive text measurement & layout

2.4 Low pattern signal View on GitHub

Open-Source Code Quality, Security and Technical Debt Review

This report summarizes scanner evidence for chenglou/pretext, a TypeScript project with 50,975 GitHub stars. SynthScan examined 84,730 lines of code across 169 source files, recording 186 pattern matches distributed across 7 syntactic categories. The legacy adjusted pattern signal is 2.4 (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.4
Adjusted Signal
2.4
Raw Pattern Score
100%
Time Factor
2026-10-15
Last Push
51.0K
Stars
TypeScript
Language
84.7K
Lines of Code
169
Files
186
Pattern Hits
2026-10-31
Scan Date
0.01
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 11.2/100 · LOW

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

Hallucinated Dependency & Supply Chain Risk 0.1/100 · LOW

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

Agent Over-Engineering Ratio 1.9/100 · LOW

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

PR Review Velocity Impact 11.5/100 · LOW

Which changes need focused human review? 186 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 1MEDIUM 8LOW 177

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 186 distinct pattern matches across 7 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 Block141 hits · 136 pts
SeverityFileLineSnippetContext
LOWharness/invariants.ts1// What an app relies on in the line APIs that no recording shows, checked offline. `bun test harness` runs it in oneCOMMENT
LOWharness/invariants.ts21// The inputs are seeded draws from harness/cases (a failure names its case, at its width, half and 1.5 times it, 1 andCOMMENT
LOWharness/invariants.ts41// - held handles, and their structuredClone() copies, lay out as before after the same texts are prepared with letterCOMMENT
LOWharness/icu.test.ts1// The library's port of ICU's rule-based break iterator and its packed tables (src/line-breaks.ts, src/graphemes.ts)COMMENT
LOWharness/cli.ts1// bun harness <command> [--browser=chrome|firefox|webkit-host|safari|ios|all] [--cases=<file.ndjson>]COMMENT
LOWharness/cli.ts21// safari records webkit-host and installed Safari's sample, and prints whether they agreeCOMMENT
LOWharness/offline-equal.ts1// `bun harness equal <ref> --offline`: whether two builds' src/ give the same results on the invariants' stand-in CanvaCOMMENT
LOWharness/browsers.ts1// The browsers a job runs in, and the environment key a recording is kept under.COMMENT
LOWharness/browsers.ts141}COMMENT
LOWharness/observe.ts1// How `record` reads the browser's own layout of a case. The DOM part runs in the page; the line functions below it alsCOMMENT
LOWharness/types.ts1// The shapes the harness passes between its files: a case, what the browser recorded for it, and what a library buildCOMMENT
LOWharness/types.ts21// - `hyphenCopies`: Chrome reports a soft hyphen's box for the code point next to it too, which the recorder leaves outCOMMENT
LOWharness/predict.ts1// The library used the way an app uses it, in the page: one Canvas font string per run style, maxWidth = the case'sCOMMENT
LOWharness/watchdog.ts1// Kills its process once it holds more than 1 GB, 2 GB for bun test itself, once the process that started it is gone, oCOMMENT
LOWharness/run.ts81// Pinned Chrome and Firefox each open a window on the user's screen, so there the page is dark and its title says theCOMMENT
LOWharness/store.ts1// The files the harness keeps in git, all plain text with one entry per line, sorted, and nothing that changes from oneCOMMENT
LOWharness/bench/report.ts1// What the bench prints: the builds, then per browser, row and family or operation, base's and the candidate's cost (peCOMMENT
LOWharness/bench/texts.ts1// The bench's texts. Chat-like messages are read in order from each family's own part of the corpora, so no message,COMMENT
LOWharness/webkit-host/main.swift1// webkit-host: one background WKWebView on the system WebKit.framework, the engine installed Safari runs, so the harnesCOMMENT
LOWharness/sets/make.ts1// Makes the case files in harness/cases. Sets with a given width are written directly; the catalog, the engine facts anCOMMENT
LOWharness/sets/sample.ts1// The real-usage sample: paragraphs drawn in proportion to how often apps lay them out, from weights.json, with aCOMMENT
LOWharness/sets/widths.ts1// The widths where each browser's lines change, and the rules that cut a generated set down to them.COMMENT
LOWharness/sets/rich.ts1// Rich-inline templates: paragraphs of spans, which the adapter lays out with rich-inline (one item per run, a chip asCOMMENT
LOWharness/sets/rich.ts21// to a ZWSP in another item, and a soft hyphen after a space in an item that continues a run from an earlier item,COMMENT
LOWharness/sets/rich.ts41// follows, beside the same message without keep-all; a mention chip inside a Korean word; and Japanese whose bold runCOMMENT
LOWharness/sets/rich.ts61// moves to the next line with them;COMMENT
LOWharness/sets/rich.ts81// line it lays out again between graphemes (itemEndHalts in src/line-break.ts). Each is three or four characters, soCOMMENT
LOWharness/sets/rich.ts101// paragraph of one item, which the adapter writes with rich-inline for the empty span and whose lines are itsCOMMENT
LOWharness/sets/rich.ts121// the space fits its line and the space doesn't, all three browsers start the next line with the ZWSP, which holdsCOMMENT
LOWharness/sets/rich.ts141// the same item without the ZWNJ, whose lines all carry it. In Chrome both templates also have other lines thanCOMMENT
LOWharness/sets/rich.ts161// start edge of its own, a segment a line can end after (getOpeningFit); a padded item of a space, a tab and aCOMMENT
LOWharness/sets/rich.ts181// moves it down (ENGINE_FOLLOWUPS.md, White space and controls): in 16px Courier New, whose hyphen is as wide as itsCOMMENT
LOWharness/sets/facts.ts1// main's engine facts as browser cases. When this set was made, src/layout.test.ts pinned 36 rules main learned aboutCOMMENT
LOWharness/sets/catalog.ts1// The behaviour catalog's templates, before widths.ts cuts them. Eleven sources:COMMENT
LOWharness/sets/data/LineBreak-17.0.0.txt1# LineBreak-17.0.0.txtCOMMENT
LOWharness/sets/data/LineBreak-17.0.0.txt21# "AI", "AK", "AL", "AP", "AS", "B2", "BA", "BB", "CB", "CJ",COMMENT
LOWharness/sets/data/LineBreak-17.0.0.txt41#COMMENT
LOWscripts/generate-engine-break-data.ts1// Generates src/generated/engine-break-data.ts, the tables behind Chrome's and Safari'sCOMMENT
LOWscripts/generate-engine-break-data.ts21// - char.brk: the brkitr/char.brk entry of Chrome 153.0.8010.53's icudtl.dat, the same bytesCOMMENT
LOWscripts/generate-engine-break-data.ts41// firefox-156/, from Firefox 155.0.1's source tree. Firefox 156.0's source tree has the same twoCOMMENT
LOWscripts/generate-engine-break-data.ts541// shape_result.cc:977-990; UnicodeProperties.h:350-355): Arabic, Mongolian, Syriac, Mandaic,COMMENT
LOWscripts/generate-engine-break-data.ts821const nextSource = `// Generated by scripts/generate-engine-break-data.ts from scripts/engine-data/.COMMENT
LOWscripts/generate-webkit-generic-families.ts1// Generates src/generated/webkit-generic-families.ts, what Safari's page resolves the genericCOMMENT
LOWscripts/generate-webkit-generic-families.ts21// WebKit's rules on Core Text's answer: a name with a leading '.' isn't used and the settings'COMMENT
LOWpages/demos/wrap-geometry.ts121// Given one allowed horizontal interval and a set of blocked intervals,COMMENT
LOWsrc/prepare.ts101COMMENT
LOWsrc/prepare.ts241// shaping run the cluster is in and spaces only its spaces (ComputeSpacing,COMMENT
LOWsrc/prepare.ts281COMMENT
LOWsrc/prepare.ts361 // Whether text segments take emergency breaks between graphemes: an atomic rich item,COMMENT
LOWsrc/prepare.ts381 // walkers, layout()'s count and rich-inline layout read where the scan gives no break.COMMENT
LOWsrc/prepare.ts641}COMMENT
LOWsrc/prepare.ts681// Blink (Chrome 153) hangs a run of U+3000 that ends a line, as it hangs spaces: ShapingLineBreakerCOMMENT
LOWsrc/line-break.ts21const BREAK_AFTER_KINDS = 1 << SPACE | 1 << ZERO_WIDTH_BREAK | 1 << SOFT_HYPHEN | 1 << PRESERVED_SPACE | 1 << TABCOMMENT
LOWsrc/line-break.ts41 // Per segment, width a line that starts with it adds back, which its width leaves outCOMMENT
LOWsrc/line-break.ts61COMMENT
LOWsrc/line-break.ts81// src/rich-inline.ts);COMMENT
LOWsrc/line-break.ts141// What a line's start leaves out, by a segment's flags: a collapsible space, a soft hyphen, and aCOMMENT
LOWsrc/line-break.ts421// between graphemes breaks before the white space instead. But Gecko breaks only after a run ofCOMMENT
LOWsrc/line-break.ts501 // so in a rich-inline paragraph the run of preserved spaces that hang goes on, with whatCOMMENT
LOWsrc/line-break.ts541 let lineEndGraphemeIndex = lineStartGraphemeIndexCOMMENT
81 more matches not shown…
Hyper-Verbose Identifiers33 hits · 33 pts
SeverityFileLineSnippetContext
LOWharness/sets/catalog.ts293export function letterSpacedLigatureTemplates(): Template[] {CODE
LOWscripts/build-demo-site.ts78function rewriteDemoLinksForStaticRoot(html: string, targetRelativePath: string): string {CODE
LOWpages/demos/dynamic-layout.ts863 requestAnimationFrame(function renderAndMaybeScheduleAnotherRender(now) {CODE
LOWpages/demos/markdown-chat.model.ts219export function createPreparedChatMessages(): PreparedChatMessage[] {CODE
LOWpages/demos/markdown-chat.model.ts496function buildPreparedInlineBlocks(CODE
LOWpages/demos/markdown-chat.model.ts845function stripSingleTrailingNewline(text: string): string {CODE
LOWpages/demos/wrap-geometry.ts73export function getPolygonIntervalForBand(CODE
LOWpages/demos/editorial-engine.ts558function isTextSelectionInteractionActive(): boolean {CODE
LOWpages/demos/editorial-engine.ts565 scheduledRaf = requestAnimationFrame(function renderAndMaybeScheduleEditorialFrame(now) {CODE
LOWpages/demos/justification-comparison.ts74 requestAnimationFrame(function syncCssOverlayAfterLayout() {CODE
LOWpages/demos/justification-comparison.model.ts238function buildMeasuredLineFromLayoutResult(CODE
LOWpages/demos/justification-comparison.model.ts353function getLineStatsFromBreakCandidates(CODE
LOWpages/demos/justification-comparison.model.ts405function buildMeasuredLineFromCandidateRange(CODE
LOWpages/demos/masonry/index.ts103function getOrCreateCardNode(cardIndex: number): HTMLDivElement {CODE
LOWpages/demos/masonry/index.ts125 scheduledRaf = requestAnimationFrame(function renderAndMaybeScheduleAnotherRender() {CODE
LOWsrc/prepare.ts57function countRenderedSpacingGraphemes(text: string, kind: SegmentKindCode, graphemeTable: GraphemeTable): number {CODE
LOWsrc/line-break.ts253export function normalizePreparedLineStart(CODE
LOWsrc/line-break.ts1092function stepPreparedSimpleLineGeometry(CODE
LOWsrc/line-break.ts1169export function stepPreparedLineGeometryFromStart(CODE
LOWsrc/gecko-line-breaks.ts75function isClusterExtenderExcludingJoiners(cp: number): boolean {CODE
LOWsrc/gecko-line-breaks.ts81function isEastAsianWidthFHWExcludingEmoji(widths: ClassTable, cp: number): boolean {CODE
LOWsrc/gecko-line-breaks.ts122export function isSpaceCombiningSequenceTail(text: string, from: number): boolean {CODE
LOWsrc/gecko-line-breaks.ts316function hasCompressedLeadingWhitespace(source: string, skipped: Uint8Array, is8bit: boolean, preserveWhiteSpace: booleaCODE
LOWsrc/measurement.ts1274function countLigaturesOnFirstLetter(seg: string, ends: Int32Array, advances: number[], measurement: FontMeasurement, emCODE
LOWsrc/line-breaks.ts872export function getWebKitBreakBetweenItems(previous: string, next: string, keepAll: boolean, language: string | null): bCODE
LOWsrc/layout.test.ts198function reconstructFromLineBoundaries(CODE
LOWsrc/analysis.ts125export function removeSkippableSegmentBreaks(text: string, profile: AnalysisProfile, language: string | null = null): stCODE
LOWsrc/analysis.ts167function getTrailingCollapsibleStart(text: string, from: number, profile: AnalysisProfile): number {CODE
LOWsrc/analysis.ts195function normalizeWhitespacePreWrap(text: string): string {CODE
LOWsrc/analysis.ts583function removeItemsSkippableSegmentBreaks(text: string, starts: number[], profile: AnalysisProfile, language: string | CODE
LOWsrc/rich-inline.ts182function getInternalPreparedRichInline(prepared: PreparedRichInline): InternalPreparedRichInline {CODE
LOWsrc/rich-inline.ts1110export function layoutNextRichInlineLineRange(CODE
LOWsrc/rich-inline.ts1192export function materializeRichInlineLineRange(CODE
AI Slop Vocabulary8 hits · 22 pts
SeverityFileLineSnippetContext
MEDIUMharness/browsers.ts564 const marker = JSON.stringify(`about:blank#pretext-harness-${jobId}`)CODE
MEDIUMharness/webkit-host/build.sh25# The harness runs only a host built from main.swift as it is (harness/browsers.ts).COMMENT
MEDIUMharness/sets/make.ts9// bun harness/sets/make.ts cut <set> # the cut cases, into harness/cases/<set>.ndjson, withCOMMENT
MEDIUMharness/sets/make.ts12// # template of the set (harness/README.md, How cases grow)COMMENT
MEDIUMharness/sets/facts.ts6// those of main before #340 (harness/README.md, Adding a case), and the number names its family, so both stay as theCOMMENT
MEDIUM⚡pages/demos/masonry/shower-thoughts.json1["Men's public restrooms are laid out all wrong. It should be urinal, stall, urinal, stall, urinal instead of urinal, urCODE
MEDIUM⚡pages/demos/masonry/shower-thoughts.json1["Men's public restrooms are laid out all wrong. It should be urinal, stall, urinal, stall, urinal instead of urinal, urCODE
LOW⚡pages/demos/masonry/shower-thoughts.json1["Men's public restrooms are laid out all wrong. It should be urinal, stall, urinal, stall, urinal instead of urinal, urCODE
Synthetic Comment Markers1 hit · 8 pts
SeverityFileLineSnippetContext
HIGH⚡pages/demos/masonry/shower-thoughts.json1["Men's public restrooms are laid out all wrong. It should be urinal, stall, urinal, stall, urinal instead of urinal, urCODE
Modern AI Meta-Vocabulary1 hit · 2 pts
SeverityFileLineSnippetContext
MEDIUMharness/sets/data/LineBreak-17.0.0.txt1927B77D..B797 ; H3 # Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAHCODE
Slop Phrases1 hit · 2 pts
SeverityFileLineSnippetContext
LOW⚡pages/demos/masonry/shower-thoughts.json1["Men's public restrooms are laid out all wrong. It should be urinal, stall, urinal, stall, urinal instead of urinal, urCODE
Fake / Example Data1 hit · 1 pts
SeverityFileLineSnippetContext
LOWharness/sets/sample.ts457 () => `192.168.${rng.int(255)}.${rng.int(255)}`, () => `+1 (415) 555-${n(4)}`, () => 'user@example.com', () => 'N/A'CODE