From 5fde4de51a3c4da8922ec986f65d9a045a5a24fa Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 7 Jul 2026 05:11:06 -0700 Subject: [PATCH] fix(review): rename ev: log keys to event: for Loki/Sentry visibility The structured-logging convention expects an "event:" key so log lines are queryable in Loki and forwarded correctly by the Sentry forwarder. ~60 sites across src/review, src/services, src/db, and src/queue used the shorthand "ev:" instead, making them invisible to both. A handful of sites already had a distinct "event:" key in the same object literal; those got a semantically specific name ("errorType:", "auditEventType:") instead of a colliding rename. --- src/db/repositories.ts | 6 ++-- src/queue/processors.ts | 20 ++++++------- src/review/alerts.ts | 2 +- src/review/auto-apply.ts | 8 ++--- src/review/auto-tune.ts | 4 +-- .../linked-issue-label-propagation-fetch.ts | 2 +- src/review/outcomes-wire.ts | 18 +++++------ src/review/parity-wire.ts | 2 +- src/review/prompt-injection.ts | 2 +- src/review/rag-index.ts | 8 ++--- src/review/rag.ts | 2 +- src/review/selftune-wire.ts | 4 +-- src/review/submitter-reputation.ts | 2 +- src/review/visual/preview-url.ts | 8 ++--- src/review/visual/shot.ts | 30 +++++++++---------- src/services/notify-discord.ts | 6 ++-- src/services/review-recap.ts | 2 +- 17 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/db/repositories.ts b/src/db/repositories.ts index 93623eb0c5..b4ccb529a2 100644 --- a/src/db/repositories.ts +++ b/src/db/repositories.ts @@ -2479,7 +2479,7 @@ export async function isGlobalAgentFrozen(env: Env): Promise { try { const row = await env.DB.prepare("SELECT frozen FROM global_agent_controls WHERE id = 'singleton'").first<{ frozen: number }>(); if (!row) { - console.warn(JSON.stringify({ ev: "global_kill_switch_row_missing", message: "global_agent_controls has no singleton row — treating as unfrozen; re-run migrations or re-seed the row" })); + console.warn(JSON.stringify({ event: "global_kill_switch_row_missing", message: "global_agent_controls has no singleton row — treating as unfrozen; re-run migrations or re-seed the row" })); if (processLocalGlobalAgentFrozen === null) processLocalGlobalAgentFrozen = false; return processLocalGlobalAgentFrozen === true; } @@ -2488,8 +2488,8 @@ export async function isGlobalAgentFrozen(env: Env): Promise { return frozen; } catch (error) { const message = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200); - console.warn(JSON.stringify({ ev: "global_kill_switch_read_error", message })); - if (processLocalGlobalAgentFrozen === true) { console.warn(JSON.stringify({ ev: "global_kill_switch_read_error_fail_closed", message: "process-local cache shows frozen=1 — halting agent actions despite the read error" })); return true; } + console.warn(JSON.stringify({ event: "global_kill_switch_read_error", message })); + if (processLocalGlobalAgentFrozen === true) { console.warn(JSON.stringify({ event: "global_kill_switch_read_error_fail_closed", message: "process-local cache shows frozen=1 — halting agent actions despite the read error" })); return true; } return false; } } diff --git a/src/queue/processors.ts b/src/queue/processors.ts index 026ac22780..8615e1db5c 100644 --- a/src/queue/processors.ts +++ b/src/queue/processors.ts @@ -3927,7 +3927,7 @@ async function scheduleTrailingIssueLinkedReReview( } catch (error) { console.log( JSON.stringify({ - ev: "issue_link_trailing_enqueue_failed", + event: "issue_link_trailing_enqueue_failed", repoFullName, pull: prNumber, message: errorMessage(error).slice(0, 120), @@ -3970,7 +3970,7 @@ async function wakeOverCapSiblingPullRequests( } catch (error) { console.log( JSON.stringify({ - ev: "contributor_cap_wake_enqueue_failed", + event: "contributor_cap_wake_enqueue_failed", repoFullName, pull: prNumber, message: errorMessage(error).slice(0, 120), @@ -6593,7 +6593,7 @@ async function resolvePullRequestFilesForReview( if (fetched.length > 0) { console.log( JSON.stringify({ - ev: "review_files_fetched_inline", + event: "review_files_fetched_inline", repository: args.repoFullName, pullNumber: args.pullNumber, files: fetched.length, @@ -8151,7 +8151,7 @@ async function maybePublishPrPublicSurface( } console.log( JSON.stringify({ - ev: "type_label_decision", + event: "type_label_decision", repoFullName, pull: pr.number, applied: true, @@ -8162,7 +8162,7 @@ async function maybePublishPrPublicSurface( } catch (error) { console.log( JSON.stringify({ - ev: "type_label_error", + event: "type_label_error", repoFullName, pull: pr.number, message: errorMessage(error).slice(0, 150), @@ -8172,7 +8172,7 @@ async function maybePublishPrPublicSurface( } else { console.log( JSON.stringify({ - ev: "type_label_decision", + event: "type_label_decision", repoFullName, pull: pr.number, applied: false, @@ -10007,7 +10007,7 @@ async function maybePublishPrPublicSurface( ).catch((error) => console.log( JSON.stringify({ - ev: "recapture_enqueue_failed", + event: "recapture_enqueue_failed", repoFullName, pull: pr.number, message: errorMessage(error).slice(0, 120), @@ -10018,7 +10018,7 @@ async function maybePublishPrPublicSurface( } catch (error) { console.log( JSON.stringify({ - ev: "visual_capture_error", + event: "visual_capture_error", repoFullName, pull: pr.number, message: errorMessage(error).slice(0, 200), @@ -10046,7 +10046,7 @@ async function maybePublishPrPublicSurface( incr("gittensory_review_memory_suppressed_total", { repo: repoFullName }); console.log( JSON.stringify({ - ev: "review_memory_applied", + event: "review_memory_applied", repoFullName, pull: pr.number, suppressedCount, @@ -10057,7 +10057,7 @@ async function maybePublishPrPublicSurface( } catch (error) { console.log( JSON.stringify({ - ev: "review_memory_error", + event: "review_memory_error", repoFullName, pull: pr.number, message: errorMessage(error).slice(0, 200), diff --git a/src/review/alerts.ts b/src/review/alerts.ts index d6d6c2c23b..00be9edfc0 100644 --- a/src/review/alerts.ts +++ b/src/review/alerts.ts @@ -268,6 +268,6 @@ export async function runAnomalyAlerts(env: Env, config: AlertAgentConfig, deps: try { await fetch(webhookUrl, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal: AbortSignal.timeout(10_000) }); } catch (error) { - console.log(JSON.stringify({ ev: "anomaly_alert_error", project: config.slug, message: String(error).slice(0, 200) })); + console.log(JSON.stringify({ event: "anomaly_alert_error", project: config.slug, message: String(error).slice(0, 200) })); } } diff --git a/src/review/auto-apply.ts b/src/review/auto-apply.ts index 7f78a020bc..aa0ff433a8 100644 --- a/src/review/auto-apply.ts +++ b/src/review/auto-apply.ts @@ -339,7 +339,7 @@ export async function runAutoApplyRecommendations(env: StorageEnv, ctx: AutoAppl const payload = rec.overridePayload; if (!isStrictlyTightening(payload, liveFloor, liveCap)) continue; const res = await applyOverrideRecommendation(env, ctx.project, payload, { force: false, soakMs: SHADOW_SOAK_MS, nowMs: ctx.nowMs }); - console.log(JSON.stringify({ ev: "auto_apply_shadowed", project: ctx.project, reason: res.reason })); + console.log(JSON.stringify({ event: "auto_apply_shadowed", project: ctx.project, reason: res.reason })); break; // one pending soak at a time } } @@ -359,12 +359,12 @@ export async function runAutoApplyRecommendations(env: StorageEnv, ctx: AutoAppl await writeLiveOverride(env, ctx.project, shadow.override); await deleteShadowOverride(env, ctx.project); await recordOverrideAudit(env, ctx.project, "override_promoted", { override: shadow.override, reason: gate.reason }); - console.log(JSON.stringify({ ev: "auto_apply_promoted", project: ctx.project, override: describeOverride(shadow.override) })); + console.log(JSON.stringify({ event: "auto_apply_promoted", project: ctx.project, override: describeOverride(shadow.override) })); } else { - console.log(JSON.stringify({ ev: "auto_apply_hold", project: ctx.project, reason: gate.reason })); + console.log(JSON.stringify({ event: "auto_apply_hold", project: ctx.project, reason: gate.reason })); } } } catch (error) { - console.log(JSON.stringify({ ev: "auto_apply_error", project: ctx.project, message: String(error).slice(0, 160) })); + console.log(JSON.stringify({ event: "auto_apply_error", project: ctx.project, message: String(error).slice(0, 160) })); } } diff --git a/src/review/auto-tune.ts b/src/review/auto-tune.ts index ef9c0a221d..4e83a288dd 100644 --- a/src/review/auto-tune.ts +++ b/src/review/auto-tune.ts @@ -116,7 +116,7 @@ export async function applyAutoTune(flags: FlagStore, report: GateEvalReport): P await flags.setFlag(`holdonly:${action.project}`, true); engaged.push(action); } catch (error) { - console.log(JSON.stringify({ ev: "auto_tune_error", project: action.project, message: String(error).slice(0, 120) })); + console.log(JSON.stringify({ event: "auto_tune_error", project: action.project, message: String(error).slice(0, 120) })); } } return engaged; @@ -198,7 +198,7 @@ export async function applyCloseAutoTune(flags: FlagStore, report: GateEvalRepor await flags.setFlag(`closehold:${action.project}`, true); engaged.push(action); } catch (error) { - console.log(JSON.stringify({ ev: "close_tune_error", project: action.project, message: String(error).slice(0, 120) })); + console.log(JSON.stringify({ event: "close_tune_error", project: action.project, message: String(error).slice(0, 120) })); } } return engaged; diff --git a/src/review/linked-issue-label-propagation-fetch.ts b/src/review/linked-issue-label-propagation-fetch.ts index c52c5e8472..03f6b3faa9 100644 --- a/src/review/linked-issue-label-propagation-fetch.ts +++ b/src/review/linked-issue-label-propagation-fetch.ts @@ -74,7 +74,7 @@ async function resolveIssueLabelsForPropagation( if (kept.length < allLabels.length && allLabels.length > 0) { console.log( JSON.stringify({ - ev: "linked_issue_label_propagation_filtered", + event: "linked_issue_label_propagation_filtered", repoFullName: args.repoFullName, issueNumber: result.facts.number, reason: maintainerAuthored ? "strict_label_requires_direct_ownership" : "no_direct_ownership_match", diff --git a/src/review/outcomes-wire.ts b/src/review/outcomes-wire.ts index 31b47477c3..2f7fcc76ba 100644 --- a/src/review/outcomes-wire.ts +++ b/src/review/outcomes-wire.ts @@ -70,7 +70,7 @@ export async function isHoldOnly(env: Env, project: string): Promise { } catch (error) { console.warn( JSON.stringify({ - ev: "flags_read_error", + event: "flags_read_error", message: errorMessage(error).slice(0, 120), }), ); @@ -96,7 +96,7 @@ export async function isCloseHoldOnly( } catch (error) { console.warn( JSON.stringify({ - ev: "flags_read_error", + event: "flags_read_error", message: errorMessage(error).slice(0, 120), }), ); @@ -136,7 +136,7 @@ async function listEngagedProjectScopes(env: Env): Promise<{ holdonly: string[]; } catch (error) { console.warn( JSON.stringify({ - ev: "flags_read_error", + event: "flags_read_error", message: errorMessage(error).slice(0, 120), }), ); @@ -242,8 +242,8 @@ async function appendReviewAudit( } catch (error) { console.warn( JSON.stringify({ - ev: "review_audit_record_error", - event: input.eventType, + event: "review_audit_record_error", + auditEventType: input.eventType, project: input.project, message: errorMessage(error).slice(0, 160), }), @@ -331,7 +331,7 @@ export async function recordPrOutcome( }).catch((error) => console.warn( JSON.stringify({ - ev: "pr_outcome_audit_error", + event: "pr_outcome_audit_error", message: errorMessage(error).slice(0, 160), }), ), @@ -554,18 +554,18 @@ export async function runSelfTuneBreaker(env: Env): Promise { const closeClearCandidates = new Set([...report.rows.map((row) => row.project), ...engagedScopes.closehold]); for (const project of mergeClearCandidates) { if (await maybeAutoClearHoldOnly(flags, report, project, nowMs)) { - console.log(JSON.stringify({ ev: "breaker_auto_cleared", project })); + console.log(JSON.stringify({ event: "breaker_auto_cleared", project })); } } for (const project of closeClearCandidates) { if (await maybeAutoClearCloseHoldOnly(flags, report, project, nowMs)) { - console.log(JSON.stringify({ ev: "close_breaker_auto_cleared", project })); + console.log(JSON.stringify({ event: "close_breaker_auto_cleared", project })); } } } catch (error) { console.warn( JSON.stringify({ - ev: "breaker_tick_error", + event: "breaker_tick_error", message: errorMessage(error).slice(0, 200), }), ); diff --git a/src/review/parity-wire.ts b/src/review/parity-wire.ts index 5c8ef67a49..918e904006 100644 --- a/src/review/parity-wire.ts +++ b/src/review/parity-wire.ts @@ -161,7 +161,7 @@ export async function recordNativeGateDecision( .run(); } catch (error) { // Telemetry must never break finalization. - console.warn(JSON.stringify({ ev: "parity_audit_record_error", project, pr: input.pullNumber, message: errorMessage(error).slice(0, 200) })); + console.warn(JSON.stringify({ event: "parity_audit_record_error", project, pr: input.pullNumber, message: errorMessage(error).slice(0, 200) })); } } diff --git a/src/review/prompt-injection.ts b/src/review/prompt-injection.ts index f33ce8d875..1d25df7c2a 100644 --- a/src/review/prompt-injection.ts +++ b/src/review/prompt-injection.ts @@ -86,6 +86,6 @@ export function neutralizePromptInjection(text: string): { text: string; injecte * verdict. Returns the safe title for the prompt. (#271 review-path injection) */ export function safeReviewTitle(target: { title?: string; repo?: string; number?: number }): string { const { text, injected } = neutralizePromptInjection(target.title ?? ""); - if (injected) console.log(JSON.stringify({ ev: "prompt_injection_neutralized", repo: target.repo, pr: target.number, field: "title" })); + if (injected) console.log(JSON.stringify({ event: "prompt_injection_neutralized", repo: target.repo, pr: target.number, field: "title" })); return text; } diff --git a/src/review/rag-index.ts b/src/review/rag-index.ts index 16c1a8221c..39e4a307e6 100644 --- a/src/review/rag-index.ts +++ b/src/review/rag-index.ts @@ -117,7 +117,7 @@ async function fetchRepoTree(env: Env, repoFullName: string, ref: string, token: } return entries; } catch (error) { - console.error(JSON.stringify({ level: "error", event: "rag_index_tree_error", ev: "rag_index_tree_error", repo: repoFullName, message: String(error).slice(0, 200) })); + console.error(JSON.stringify({ level: "error", event: "rag_index_tree_error", repo: repoFullName, message: String(error).slice(0, 200) })); return null; } } @@ -220,7 +220,7 @@ export async function listStoredChunkPaths(infra: ReturnType(); return (rows.results ?? []).map((row) => row.path).filter((path) => typeof path === "string" && path.length > 0); } catch (error) { - console.error(JSON.stringify({ level: "error", event: "rag_list_paths_error", ev: "rag_list_paths_error", project, repo, message: String(error).slice(0, 200) })); + console.error(JSON.stringify({ level: "error", event: "rag_list_paths_error", project, repo, message: String(error).slice(0, 200) })); return []; } } @@ -312,7 +312,7 @@ export async function indexRepo( } } console.log( - JSON.stringify({ ev: "rag_index_repo", project, repo: repoFullName, files: filesIndexed, indexed: upserted, capped }), + JSON.stringify({ event: "rag_index_repo", project, repo: repoFullName, files: filesIndexed, indexed: upserted, capped }), ); return { indexed: upserted, files: filesIndexed, capped }; } catch (error) { @@ -379,7 +379,7 @@ export async function reindexChangedPaths( } } console.log( - JSON.stringify({ ev: "rag_reindex_paths", project, repo: repoFullName, paths: unique.length, files: filesIndexed, indexed: upserted, capped }), + JSON.stringify({ event: "rag_reindex_paths", project, repo: repoFullName, paths: unique.length, files: filesIndexed, indexed: upserted, capped }), ); return { indexed: upserted, files: filesIndexed, capped }; } catch (error) { diff --git a/src/review/rag.ts b/src/review/rag.ts index 552ed41003..e85560813a 100644 --- a/src/review/rag.ts +++ b/src/review/rag.ts @@ -463,7 +463,7 @@ export async function retrieveContextWithMetrics( // context was injected) instead of flying blind — feeds tuning of minScore/topK + the /stats readout. console.log( JSON.stringify({ - ev: "rag_retrieve", + event: "rag_retrieve", project: opts.project, repo: opts.repo, candidates: metrics.candidates, diff --git a/src/review/selftune-wire.ts b/src/review/selftune-wire.ts index 840f4bc455..8e670032b8 100644 --- a/src/review/selftune-wire.ts +++ b/src/review/selftune-wire.ts @@ -134,10 +134,10 @@ export async function runSelfTune(env: Env): Promise { nowMs, }); } catch (error) { - console.warn(JSON.stringify({ ev: "selftune_repo_error", repo: repoFullName, message: errorMessage(error).slice(0, 200) })); + console.warn(JSON.stringify({ event: "selftune_repo_error", repo: repoFullName, message: errorMessage(error).slice(0, 200) })); } } } catch (error) { - console.warn(JSON.stringify({ ev: "selftune_error", message: errorMessage(error).slice(0, 200) })); + console.warn(JSON.stringify({ event: "selftune_error", message: errorMessage(error).slice(0, 200) })); } } diff --git a/src/review/submitter-reputation.ts b/src/review/submitter-reputation.ts index 82d4866c8c..72558c8615 100644 --- a/src/review/submitter-reputation.ts +++ b/src/review/submitter-reputation.ts @@ -213,7 +213,7 @@ export async function recordSubmissionOutcome(env: Env, project: string, submitt .bind(project, submitter) .run(); } catch (error) { - console.log(JSON.stringify({ ev: "reputation_record_error", message: String(error).slice(0, 150) })); + console.log(JSON.stringify({ event: "reputation_record_error", message: String(error).slice(0, 150) })); } } diff --git a/src/review/visual/preview-url.ts b/src/review/visual/preview-url.ts index f49bcc520b..2d8c6f5e4c 100644 --- a/src/review/visual/preview-url.ts +++ b/src/review/visual/preview-url.ts @@ -106,7 +106,7 @@ export async function getLatestDeploymentStatus(params: { // 404 → the ref genuinely has no deployments. Any other failure (403 missing scope, rate limit, 5xx) is // NOT "no preview"; report `error` so the caller keeps polling rather than showing a false terminal state. if (error instanceof PreviewGitHubError && error.status === 404) return { url: null, failed: false }; - console.log(JSON.stringify({ ev: "deployment_lookup_error", repo: `${params.repo.owner}/${params.repo.repo}`, selector, message: String(error).slice(0, 200) })); + console.log(JSON.stringify({ event: "deployment_lookup_error", repo: `${params.repo.owner}/${params.repo.repo}`, selector, message: String(error).slice(0, 200) })); return { url: null, failed: false, error: true }; } const ids = deployments.map((d) => d.id).filter((id): id is number => id != null); @@ -117,7 +117,7 @@ export async function getLatestDeploymentStatus(params: { apiVersion: params.apiVersion, rateLimitAdmissionKey: params.rateLimitAdmissionKey, }).catch((error) => { - console.log(JSON.stringify({ ev: "deployment_status_error", deployment: id, message: String(error).slice(0, 200) })); + console.log(JSON.stringify({ event: "deployment_status_error", deployment: id, message: String(error).slice(0, 200) })); return [] as Array<{ state?: string; environment_url?: string }>; }), ), @@ -195,7 +195,7 @@ export async function findPreviewUrlFromChecks(params: { if (url) return url; } } catch (error) { - console.log(JSON.stringify({ ev: "preview_from_checks_error", repo: `${params.repo.owner}/${params.repo.repo}`, message: String(error).slice(0, 200) })); + console.log(JSON.stringify({ event: "preview_from_checks_error", repo: `${params.repo.owner}/${params.repo.repo}`, message: String(error).slice(0, 200) })); } return null; } @@ -228,7 +228,7 @@ export async function findPreviewUrlFromPrComments(params: { if (url) return url; } } catch (error) { - console.log(JSON.stringify({ ev: "preview_from_comments_error", repo: `${params.repo.owner}/${params.repo.repo}`, message: String(error).slice(0, 200) })); + console.log(JSON.stringify({ event: "preview_from_comments_error", repo: `${params.repo.owner}/${params.repo.repo}`, message: String(error).slice(0, 200) })); } return null; } diff --git a/src/review/visual/shot.ts b/src/review/visual/shot.ts index 0618613542..17282eb719 100644 --- a/src/review/visual/shot.ts +++ b/src/review/visual/shot.ts @@ -158,12 +158,12 @@ async function captureBoundedFullPageShot(page: ScreenshotPage, viewport: Viewpo ]); clearTimeout(heightProbeTimeoutId as ReturnType); if (height === null) { - console.log(JSON.stringify({ ev: "render_screenshot_height_probe_timeout", timeoutMs: SCREENSHOT_HEIGHT_PROBE_TIMEOUT_MS })); + console.log(JSON.stringify({ event: "render_screenshot_height_probe_timeout", timeoutMs: SCREENSHOT_HEIGHT_PROBE_TIMEOUT_MS })); return null; } const pixelArea = viewport.width * height; if (height > MAX_SCREENSHOT_HEIGHT || pixelArea > MAX_SCREENSHOT_PIXELS) { - console.log(JSON.stringify({ ev: "render_screenshot_too_large", width: viewport.width, height, maxHeight: MAX_SCREENSHOT_HEIGHT, maxPixels: MAX_SCREENSHOT_PIXELS })); + console.log(JSON.stringify({ event: "render_screenshot_too_large", width: viewport.width, height, maxHeight: MAX_SCREENSHOT_HEIGHT, maxPixels: MAX_SCREENSHOT_PIXELS })); return null; } @@ -172,11 +172,11 @@ async function captureBoundedFullPageShot(page: ScreenshotPage, viewport: Viewpo new Promise((resolve) => setTimeout(() => resolve(null), SCREENSHOT_TIMEOUT_MS)), ]); if (!shot) { - console.log(JSON.stringify({ ev: "render_screenshot_timeout", timeoutMs: SCREENSHOT_TIMEOUT_MS })); + console.log(JSON.stringify({ event: "render_screenshot_timeout", timeoutMs: SCREENSHOT_TIMEOUT_MS })); return null; } if (shot.byteLength > MAX_SCREENSHOT_BYTES) { - console.log(JSON.stringify({ ev: "render_screenshot_bytes_too_large", bytes: shot.byteLength, maxBytes: MAX_SCREENSHOT_BYTES })); + console.log(JSON.stringify({ event: "render_screenshot_bytes_too_large", bytes: shot.byteLength, maxBytes: MAX_SCREENSHOT_BYTES })); return null; } // Re-validate against the ACTUAL rendered PNG dimensions -- these come from Chromium's rasterizer, not page @@ -184,7 +184,7 @@ async function captureBoundedFullPageShot(page: ScreenshotPage, viewport: Viewpo // rather than let through, since that's precisely what a successful spoof would look like from here. const dims = readPngDimensions(shot); if (!dims || dims.height > MAX_SCREENSHOT_HEIGHT || dims.width * dims.height > MAX_SCREENSHOT_PIXELS) { - console.log(JSON.stringify({ ev: "render_screenshot_dimensions_too_large", width: dims?.width ?? null, height: dims?.height ?? null, maxHeight: MAX_SCREENSHOT_HEIGHT, maxPixels: MAX_SCREENSHOT_PIXELS })); + console.log(JSON.stringify({ event: "render_screenshot_dimensions_too_large", width: dims?.width ?? null, height: dims?.height ?? null, maxHeight: MAX_SCREENSHOT_HEIGHT, maxPixels: MAX_SCREENSHOT_PIXELS })); return null; } return shot; @@ -201,7 +201,7 @@ export async function captureShot(env: Env, url: string, viewport: Viewport = VI // private / cloud-metadata 169.254.169.254 / etc.). Callers may resolve `url` from a deployment_status // webhook or a PR-comment preview link, so guard at this choke point regardless of how the URL was obtained. if (!url || !isSafeHttpUrl(url) || (opts.isAllowedUrl && !opts.isAllowedUrl(url))) { - console.log(JSON.stringify({ ev: "render_screenshot_blocked", url: String(url).slice(0, 120) })); + console.log(JSON.stringify({ event: "render_screenshot_blocked", url: String(url).slice(0, 120) })); return { png: null, authWalled: false }; } if (!env.BROWSER) return { png: null, authWalled: false }; @@ -222,7 +222,7 @@ export async function captureShot(env: Env, url: string, viewport: Viewport = VI if (protocol === "http:" || protocol === "https:") { const isAllowedNavigation = !request.isNavigationRequest() || !opts.isAllowedUrl || opts.isAllowedUrl(requestUrl); if (!isSafeHttpUrl(requestUrl) || !isAllowedNavigation) { - console.log(JSON.stringify({ ev: "render_screenshot_request_blocked", url: requestUrl.slice(0, 120) })); + console.log(JSON.stringify({ event: "render_screenshot_request_blocked", url: requestUrl.slice(0, 120) })); request.abort().catch(() => undefined); return; } @@ -233,14 +233,14 @@ export async function captureShot(env: Env, url: string, viewport: Viewport = VI if (opts.theme) await page.emulateMediaFeatures([{ name: "prefers-color-scheme", value: opts.theme }]); await page.goto(url, { waitUntil: "networkidle0", timeout: 20000 }); if (!isSafeHttpUrl(page.url()) || (opts.isAllowedUrl && !opts.isAllowedUrl(page.url()))) { - console.log(JSON.stringify({ ev: "render_screenshot_redirect_blocked", url, final: page.url().slice(0, 200) })); + console.log(JSON.stringify({ event: "render_screenshot_redirect_blocked", url, final: page.url().slice(0, 200) })); return { png: null, authWalled: false }; } // A protected route that redirected to a login page: don't return a screenshot of the sign-in screen — // flag it so the caller renders an honest auth placeholder. (The requested URL not itself being a login // page guards a PR that legitimately changes the login screen.) if (isAuthWallUrl(page.url()) && !isAuthWallUrl(url)) { - console.log(JSON.stringify({ ev: "render_screenshot_auth_walled", url, final: page.url().slice(0, 200) })); + console.log(JSON.stringify({ event: "render_screenshot_auth_walled", url, final: page.url().slice(0, 200) })); return { png: null, authWalled: true }; } // Full-page (not just the viewport), but bounded: before/after should include the same page position for @@ -251,7 +251,7 @@ export async function captureShot(env: Env, url: string, viewport: Viewport = VI } catch (error) { // Log before degrading to null — otherwise a networkidle0 timeout, a binding quota error, or a render // crash is indistinguishable from "no page" and the cell silently blanks. - console.log(JSON.stringify({ ev: "render_screenshot_error", mode: "binding", url, message: String(error).slice(0, 200) })); + console.log(JSON.stringify({ event: "render_screenshot_error", mode: "binding", url, message: String(error).slice(0, 200) })); return { png: null, authWalled: false }; } finally { if (browser) await browser.close().catch(() => undefined); @@ -301,7 +301,7 @@ async function waitForScrollSettle(): Promise { */ export async function captureScrollFrames(env: Env, url: string, viewport: Viewport = VIEWPORT, opts: CaptureShotOptions = {}): Promise<{ frames: Uint8Array[]; authWalled: boolean }> { if (!url || !isSafeHttpUrl(url) || (opts.isAllowedUrl && !opts.isAllowedUrl(url))) { - console.log(JSON.stringify({ ev: "render_scroll_frames_blocked", url: String(url).slice(0, 120) })); + console.log(JSON.stringify({ event: "render_scroll_frames_blocked", url: String(url).slice(0, 120) })); return { frames: [], authWalled: false }; } if (!env.BROWSER) return { frames: [], authWalled: false }; @@ -322,7 +322,7 @@ export async function captureScrollFrames(env: Env, url: string, viewport: Viewp if (protocol === "http:" || protocol === "https:") { const isAllowedNavigation = !request.isNavigationRequest() || !opts.isAllowedUrl || opts.isAllowedUrl(requestUrl); if (!isSafeHttpUrl(requestUrl) || !isAllowedNavigation) { - console.log(JSON.stringify({ ev: "render_scroll_frames_request_blocked", url: requestUrl.slice(0, 120) })); + console.log(JSON.stringify({ event: "render_scroll_frames_request_blocked", url: requestUrl.slice(0, 120) })); request.abort().catch(() => undefined); return; } @@ -333,11 +333,11 @@ export async function captureScrollFrames(env: Env, url: string, viewport: Viewp if (opts.theme) await page.emulateMediaFeatures([{ name: "prefers-color-scheme", value: opts.theme }]); await page.goto(url, { waitUntil: "networkidle0", timeout: 20000 }); if (!isSafeHttpUrl(page.url()) || (opts.isAllowedUrl && !opts.isAllowedUrl(page.url()))) { - console.log(JSON.stringify({ ev: "render_scroll_frames_redirect_blocked", url, final: page.url().slice(0, 200) })); + console.log(JSON.stringify({ event: "render_scroll_frames_redirect_blocked", url, final: page.url().slice(0, 200) })); return { frames: [], authWalled: false }; } if (isAuthWallUrl(page.url()) && !isAuthWallUrl(url)) { - console.log(JSON.stringify({ ev: "render_scroll_frames_auth_walled", url, final: page.url().slice(0, 200) })); + console.log(JSON.stringify({ event: "render_scroll_frames_auth_walled", url, final: page.url().slice(0, 200) })); return { frames: [], authWalled: true }; } // `document`/`window` below run inside the real page (the callback is serialized and executed in the @@ -362,7 +362,7 @@ export async function captureScrollFrames(env: Env, url: string, viewport: Viewp } return { frames, authWalled: false }; } catch (error) { - console.log(JSON.stringify({ ev: "render_scroll_frames_error", mode: "binding", url, message: String(error).slice(0, 200) })); + console.log(JSON.stringify({ event: "render_scroll_frames_error", mode: "binding", url, message: String(error).slice(0, 200) })); return { frames: [], authWalled: false }; } finally { if (browser) await browser.close().catch(() => undefined); diff --git a/src/services/notify-discord.ts b/src/services/notify-discord.ts index 025837ea80..0ca521dde3 100644 --- a/src/services/notify-discord.ts +++ b/src/services/notify-discord.ts @@ -108,7 +108,7 @@ async function auditExternalNotification( detail, metadata: { repoFullName: params.repoFullName, pullNumber: params.pullNumber, actionOutcome: params.outcome, ...metadata }, }).catch((error) => { - console.warn(JSON.stringify({ ev: `${provider}_notify_audit_failed`, repo: params.repoFullName, pull: params.pullNumber, message: errorMessage(error).slice(0, 120) })); + console.warn(JSON.stringify({ event: `${provider}_notify_audit_failed`, repo: params.repoFullName, pull: params.pullNumber, message: errorMessage(error).slice(0, 120) })); }); } @@ -144,7 +144,7 @@ export async function notifyActionToDiscord( await postWebhook(resolved.url, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal: AbortSignal.timeout(10_000) }, "discord"); await auditExternalNotification(env, params, "discord", "completed", "sent", { source: resolved.source }); } catch (error) { - console.warn(JSON.stringify({ ev: "discord_notify_failed", repo: params.repoFullName, pull: params.pullNumber, message: errorMessage(error).slice(0, 120) })); + console.warn(JSON.stringify({ event: "discord_notify_failed", repo: params.repoFullName, pull: params.pullNumber, message: errorMessage(error).slice(0, 120) })); await auditExternalNotification(env, params, "discord", "error", errorMessage(error).slice(0, 160), { source: resolved.source }); } } @@ -188,7 +188,7 @@ export async function notifyActionToSlack( await postWebhook(webhookUrl, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal: AbortSignal.timeout(10_000) }, "slack"); await auditExternalNotification(env, params, "slack", "completed", "sent"); } catch (error) { - console.warn(JSON.stringify({ ev: "slack_notify_failed", repo: params.repoFullName, pull: params.pullNumber, message: errorMessage(error).slice(0, 120) })); + console.warn(JSON.stringify({ event: "slack_notify_failed", repo: params.repoFullName, pull: params.pullNumber, message: errorMessage(error).slice(0, 120) })); await auditExternalNotification(env, params, "slack", "error", errorMessage(error).slice(0, 160)); } } diff --git a/src/services/review-recap.ts b/src/services/review-recap.ts index 5ccac6a724..a2d368155c 100644 --- a/src/services/review-recap.ts +++ b/src/services/review-recap.ts @@ -180,7 +180,7 @@ export async function sendReviewRecapToDiscord(env: Env, recap: ReviewRecap): Pr return { sent: true }; } catch (error) { const detail = errorMessage(error).slice(0, 160); - console.warn(JSON.stringify({ ev: "review_recap_discord_failed", repo: recap.repoFullName, message: detail })); + console.warn(JSON.stringify({ event: "review_recap_discord_failed", repo: recap.repoFullName, message: detail })); await recordAuditEvent(env, { eventType: "review_recap_notification.discord", actor: "gittensory",