Conversation
Add no-focus-ring class to exclude AI search input from global :focus-visible outline styling.
Code ReviewGreat PR overall — the error tracking system is well-designed and the threaded notification changes are clean. The refactoring wins (DRY 🔴
|
Revision history for monoscope0.1.0.0 -- YYYY-mm-dd
|
Code Review — PR #326 (Error Tracking + Threaded Notifications)Overall this is a solid, well-structured PR. The test suite is comprehensive (20 scenarios covering the full state machine, concurrency, cross-project isolation, and thread-ID persistence), the SQL uses efficient batch patterns throughout, and the 🐛 Potential Bug — Duplicate Notifications
The JOIN: JOIN apis.issues i ON i.project_id = e.project_id AND i.target_hash = e.hash
…
AND i.issue_type = ?can return multiple rows per error pattern when more than one SELECT DISTINCT ON (e.id)
e.id, e.error_data, e.state, i.id, i.title,
e.slack_thread_ts, e.discord_message_id
FROM apis.error_patterns e
JOIN apis.issues i ON i.project_id = e.project_id AND i.target_hash = e.hash
WHERE …
ORDER BY e.id, i.created_at DESC⚡ Performance — Sequential Spike Detection
forConcurrently_ errRates \errRate -> ...🔍 Design — 7 Positional
|
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
PR Review: Errors with Threaded Replies |
This comment was marked as outdated.
This comment was marked as outdated.
|
See review content posted below - full markdown review to follow |
|
test |
Revision history for monoscope0.1.0.0 -- YYYY-mm-dd
|
1 similar comment
Revision history for monoscope0.1.0.0 -- YYYY-mm-dd
|
|
PR Review part 1 of 2: BUGS. (1) createOtelTraceWithExceptionAtTime has broken UUID encoding: UUID.toText returns 36 chars with dashes, so T.replicate (32-36) returns empty string, and B16.decode fails silently. traceIdBS/spanIdBS are always empty bytes. Fix: strip dashes with T.filter before padding. (2) insertErrorQueryAndParams in Anomalies.hs is dead code: processProjectErrors now delegates to batchUpsertErrorPatterns, nothing calls insertErrorQueryAndParams. Remove it. PERFORMANCE: (3) goStdlibPrefixes is a 50-entry [Text] list scanned per Go stack frame. Use HashSet Text and check only the package segment via fst (splitDotted funcPart) for O(1) lookup. |
|
PR Review part 2 of 2: EXPORTS: (4) sendSlackAlertWith/sendDiscordAlertWith are exported but documented as Internal -- either remove from exports or drop the doc comment. STYLE: (5) errorSubscriptionAction has 3 consecutive single-binding lets (isActive, notifyEvery, actionUrl) -- combine into one let block. (6) createAndNotifyErrorIssue uses Effectful.Reader.Static.ask when ask is imported unqualified -- use ask @Config.AuthContext. (7) anomalyDetailCore uses the ampersand-LambdaCase pattern only once -- case issue.issueType of matches the rest of the file. (8) Multiple new sites use whenJust ... Relude.when -- for_ projectM is cleaner and avoids the qualified import. GOOD: void $ replaces _ <- pass throughout; WrappedEnumSC gains ToJSON/FromJSON directly eliminating ~6 duplicate via CustomJSON derivations; colIdxMap via zip cols [0..] removes sync-drift bugs; Permissions ordering fix with Ord makes >= PEdit semantically correct; sortBy before groupBy in processIssuesEnhancement is the right defensive fix; buildDrainTree removes the duplicated fold pattern; batchUpsertErrorPatterns hash-grouping correctly avoids the ON CONFLICT duplicate-row error. |
This comment was marked as outdated.
This comment was marked as outdated.
Add DISTINCT ON to notifyErrorSubscriptions to prevent duplicate notifications when multiple issues exist for the same error pattern. Switch detectErrorSpikes from sequential forM_ to forConcurrently. Remove redundant CustomJSON derivations on IssueType/RateChangeDirection.
PR Review: Errors with threaded repliesGood overall structure. The fingerprinting algorithm is well-documented with doctests, the single-CTE baseline calculation is efficient, and the WrappedEnumSC JSON/DAE.CustomJSON consolidation is a clean DRY win. A few things worth addressing: Potential bugsRace condition in detectErrorSpikes (BackgroundJobs.hs) Permissions constructor order changed silently Succinctness / package usageUnbounded forConcurrently in detectErrorSpikes and notifyErrorSubscriptions cleanPythonFunction opaque pointfree (Pkg/ErrorFingerprint.hs) Dead branch in extractGenericLineNumber occurrences_1m / occurrences_5m snake_case in a camelCase record Minor
Good changes worth calling out
|
looksLikeJson used isInfixOf for "{" which matched replacement tokens
like {integer}, {YYYY-MM-DDThh:mm:ss.sTZD}, causing tokenizeJsonLike
to split them into separate tokens and break drain clustering.
Code ReviewGreat feature addition — the error tracking state machine, log pattern detection, and notification threading all fit well into the existing architecture. Several cleanups here are excellent. Here are my observations: Highlights
Issues / suggestions1. Non-idiomatic snake_case field names in , occurrences_1m :: Int -- snake_case fields match DB column names exactly
, occurrences_5m :: Int
, occurrences_1h :: Int
, occurrences_24h :: IntHaskell record fields should be camelCase. With 2. Z-score recomputed in
let zScore = if baselineStddev > 0 then (currentRate - baselineMean) / baselineStddev else 0Pass the already-computed 3. Redundant tokenize = tok . drainContent
drainContent = \case SeedPattern c -> c; NewEvent _ c -> cUsed exactly once — inline it: 4. Destructive migration without data migration ( DROP TABLE IF EXISTS apis.errors CASCADE;This drops 5. addError acc e = HM.insertWith addCounts e.hash (1 :: Int, bool 0 1 (isJust e.userId)) acc
6. Lazy irrefutable pattern ~(subj, html) = case alertType of ...Smart optimization to avoid computing email content when 7. issueM <- Issues.selectIssueByHash pid err.hashIf multiple issues exist for the same hash (e.g., after a regression creates a second issue), this returns an arbitrary match. Ensure the underlying query orders by 8. addCounts (c1, u1) (c2, u2) = (c1 + c2, u1 + u2)With SummaryThe design is solid and the code is well-structured. Items worth addressing before merge:
|
The test was passing Nothing for service and omitting the actual service name used during OTEL ingestion (test-service), causing the computed fingerprint hash to not match the DB.
- createErrorSpikeIssue now receives the already-computed z-score from detectSpikeOrDrop instead of recomputing it from mean/stddev - Inline single-use drainContent helper into tokenize composition
Code Review — Error Tracking + Log Pattern + Threaded NotificationsOverall this is a well-structured, well-tested PR. The fingerprinting, baseline/spike logic, and threading support are all coherent. Notes below focus on succinctness, correctness, and performance. Bugs / Correctness
-- grouped in Models/Apis/ErrorPatterns.hs
HM.insertWith (\(newE, n) (_, k) -> (newE, n + k)) e.hash (e, 1) m
The -- INVARIANT: every entry must end with '.' or '/' so the lookupLE prefix
-- check in isGoStdlib cannot produce false positives against sibling packages.
goStdlibPrefixes :: S.Set TextSuccinctness / Style
The point-free form with cleanPythonFunction f = foldr (\(a, b) -> T.replace a b) f
[("<lambda>", "lambda"), ("<listcomp>", "listcomp"), ("<dictcomp>", "dictcomp")]Unnecessary lazy pattern in ~(subj, html) = case alertType of ...The
case parts of
_ : rest -> listToMaybe $ mapMaybe readText rest
_ -> Nothing -- unreachable: T.splitOn always returns >= 1 element
Performance
The tuple Minor Notes
Overall the test coverage in |
Code ReviewThis is a substantial, well-structured PR. The test coverage (20 cases in 1.
|
Code Review - PR 326: Errors with threaded repliesBig feature addition overall. Architecture is sound and the batch-upsert and threading designs are well thought out. Some targeted notes below. Correctness / Potential Bugs
The state machine progresses Conciseness / GHC-extension opportunities
Current (in normalizeFunction func =
let noAddr = unwords $ filter (not . ("0x" `T.isPrefixOf`)) $ words func
noGenerics = T.takeWhile (/= '<') noAddr
noParams = T.takeWhile (/= '(') noGenerics
in T.strip noParamsWith point-free composition (no intermediate names needed): normalizeFunction =
T.strip . T.takeWhile (/= '(') . T.takeWhile (/= '<')
. unwords . filter (not . T.isPrefixOf "0x") . words
-- current
cleanPythonFunction = flip (foldr (uncurry T.replace)) ([("<lambda>", "lambda"), ...] :: [(Text, Text)])
-- clearer
cleanPythonFunction f =
foldl' (\t (k, v) -> T.replace k v t) f
[("<lambda>", "lambda"), ("<listcomp>", "listcomp"), ("<dictcomp>", "dictcomp")]
-- current
asum $ map (\ext -> T.stripSuffix ext baseName) [".js", ".ts", ".mjs", ".cjs"]
-- simpler
asum $ map (`T.stripSuffix` baseName) [".js", ".ts", ".mjs", ".cjs"]
The suffix Test Coverage
The module has rich Background jobs lack unit tests
Minor
What is good
|
Summary
Two major features: Error Tracking with Sentry-style fingerprinting and spike detection, and Log Pattern Detection using the DRAIN algorithm with baseline volume tracking. Both integrate with a new threaded notification system for Slack, Discord, Email, and PagerDuty.
Error Tracking System
module|functionformat; normalizes messages by replacing UUIDs, IPs, emails, timestamps with placeholders; uses XXHash for deterministic fingerprintsNew→Escalating→Ongoing→Resolved(withRegressedfor reactivation)notifyEveryMinutesthrottle (default 30min)Log Pattern Detection
Learning→Establishedstate; hourly volume mean + MAD stored inlog_pattern_hourly_statsNew→Acknowledged→Ignored; auto-acknowledges stale patterns after 30 daysNotification System
thread_ts, subsequent updates reply in same threadmessage_idfor reply-to referencesBackground Jobs
ErrorBaselineCalculationErrorSpikeDetectionNewErrorDetectedErrorAssignedFiveMinuteLogPatternExtractionLogPatternPeriodicProcessingLogPatternHourlyProcessingDatabase Migrations
apis.errorsandapis.error_eventstables with fingerprint indexes, triggers, anderror_escalating/error_regressedissue typessubscribed,notify_every_minutes,last_notified_aton errorsslack_thread_tsanddiscord_message_idon errors for threaded notificationsNote: Log pattern migrations (
log_patterns,log_pattern_hourly_stats, issue column extensions) were already merged vialog-patterns-chpPR as0032_log_patterns.sql.