Skip to content

Commit 72147c3

Browse files
fix(queue): stamp console.error payloads as level error
Twenty-four queue failure logs used console.error with an explicit level:"warn", which made forwardStructuredLogToSentry treat real failures as warnings. Align them with the sink and the other console.error call sites in the same files. Closes #7806 Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 299c842 commit 72147c3

4 files changed

Lines changed: 89 additions & 24 deletions

File tree

src/queue/ai-review-orchestration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ export async function runAiReviewForAdvisory(
880880
} catch (error) {
881881
console.error(
882882
JSON.stringify({
883-
level: "warn",
883+
level: "error",
884884
event: "ai_review_failed",
885885
repository: args.repoFullName,
886886
pullNumber: args.pr.number,

src/queue/processors.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ export async function buildContributorDecisionPacks(
805805
/* v8 ignore next -- defensive per-login isolation; the log-and-continue path is not exercised in tests */
806806
console.error(
807807
JSON.stringify({
808-
level: "warn",
808+
level: "error",
809809
event: "decision_pack_login_failed",
810810
login: contributorLogin,
811811
error: errorMessage(error),
@@ -1474,7 +1474,7 @@ export async function sweepRepoRegate(
14741474
).catch((error) => {
14751475
console.error(
14761476
JSON.stringify({
1477-
level: "warn",
1477+
level: "error",
14781478
event: "sweep_mark_regated_failed",
14791479
repository: repoFullName,
14801480
error: errorMessage(error),
@@ -1775,7 +1775,7 @@ export async function sweepRepoBacklogConvergence(
17751775
).catch((error) => {
17761776
console.error(
17771777
JSON.stringify({
1778-
level: "warn",
1778+
level: "error",
17791779
event: "backlog_convergence_mark_regated_failed",
17801780
repository: repoFullName,
17811781
error: errorMessage(error),
@@ -1919,7 +1919,7 @@ export async function regatePullRequest(
19191919
}
19201920
console.error(
19211921
JSON.stringify({
1922-
level: "warn",
1922+
level: "error",
19231923
event: "sweep_rereview_failed",
19241924
deliveryId,
19251925
repository: repoFullName,
@@ -3584,7 +3584,7 @@ export async function reReviewStoredPullRequest(
35843584
if (isGitHubRateLimitedError(error) || isRetryableJobError(error)) throw error;
35853585
console.error(
35863586
JSON.stringify({
3587-
level: "warn",
3587+
level: "error",
35883588
event: "pr_public_surface_failed",
35893589
deliveryId,
35903590
repository: repoFullName,
@@ -3618,7 +3618,7 @@ export async function reReviewStoredPullRequest(
36183618
).catch((error) => {
36193619
console.error(
36203620
JSON.stringify({
3621-
level: "warn",
3621+
level: "error",
36223622
event: "agent_maintenance_failed",
36233623
deliveryId,
36243624
repository: repoFullName,
@@ -5139,7 +5139,7 @@ async function processContributorEvidenceLogins(
51395139
/* v8 ignore next -- defensive per-login isolation; the log-and-continue path is not exercised in tests */
51405140
console.error(
51415141
JSON.stringify({
5142-
level: "warn",
5142+
level: "error",
51435143
event: "contributor_evidence_login_failed",
51445144
login: contributorLogin,
51455145
error: errorMessage(error),
@@ -6388,7 +6388,7 @@ async function handlePullRequestWebhookEvent(
63886388
if (isGitHubRateLimitedError(error) || isRetryableJobError(error)) throw error;
63896389
console.error(
63906390
JSON.stringify({
6391-
level: "warn",
6391+
level: "error",
63926392
event: "pr_public_surface_failed",
63936393
deliveryId,
63946394
repository: payload.repository?.full_name,
@@ -6426,7 +6426,7 @@ async function handlePullRequestWebhookEvent(
64266426
/* v8 ignore next -- best-effort: auto-maintain failures are logged, never surfaced to the gate. */
64276427
console.error(
64286428
JSON.stringify({
6429-
level: "warn",
6429+
level: "error",
64306430
event: "agent_maintenance_failed",
64316431
deliveryId,
64326432
repository: repoFullName,
@@ -6457,7 +6457,7 @@ async function handlePullRequestWebhookEvent(
64576457
/* v8 ignore next -- best-effort: a reputation-record failure is logged, never surfaced to the gate. */
64586458
console.error(
64596459
JSON.stringify({
6460-
level: "warn",
6460+
level: "error",
64616461
event: "reputation_record_failed",
64626462
deliveryId,
64636463
repository: repoFullName,
@@ -6483,7 +6483,7 @@ async function handlePullRequestWebhookEvent(
64836483
/* v8 ignore next -- best-effort: a RAG re-index enqueue failure is logged, never surfaced to the gate. */
64846484
console.error(
64856485
JSON.stringify({
6486-
level: "warn",
6486+
level: "error",
64876487
event: "rag_reindex_enqueue_failed",
64886488
deliveryId,
64896489
repository: repoFullName,
@@ -6508,7 +6508,7 @@ async function handlePullRequestWebhookEvent(
65086508
/* v8 ignore next -- best-effort: a sibling re-gate enqueue failure is logged, never surfaced to the gate. */
65096509
console.error(
65106510
JSON.stringify({
6511-
level: "warn",
6511+
level: "error",
65126512
event: "sibling_regate_enqueue_failed",
65136513
deliveryId,
65146514
repository: repoFullName,
@@ -6612,7 +6612,7 @@ async function handleIssueWebhookEvent(
66126612
/* v8 ignore next -- best-effort: an issue-cap enforcement failure is logged, never surfaced to the webhook. */
66136613
console.error(
66146614
JSON.stringify({
6615-
level: "warn",
6615+
level: "error",
66166616
event: "contributor_issue_cap_failed",
66176617
deliveryId,
66186618
repository: payload.repository?.full_name,
@@ -7013,7 +7013,7 @@ async function resolvePullRequestFilesForReview(
70137013
/* v8 ignore next -- fail-safe: an inline fetch failure degrades to the empty stored rows (byte-identical to pre-fix). */
70147014
console.error(
70157015
JSON.stringify({
7016-
level: "warn",
7016+
level: "error",
70177017
event: "review_files_inline_fetch_failed",
70187018
repository: args.repoFullName,
70197019
pullNumber: args.pullNumber,
@@ -7479,7 +7479,7 @@ export async function runLinkedIssueSatisfactionForAdvisory(
74797479
} catch (error) {
74807480
console.error(
74817481
JSON.stringify({
7482-
level: "warn",
7482+
level: "error",
74837483
event: "linked_issue_satisfaction_failed",
74847484
repository: args.repoFullName,
74857485
pullNumber: args.pr.number,
@@ -7557,7 +7557,7 @@ export async function runContentLaneDeliverableCheckForAdvisory(
75577557
* calls (e.g. a DB-backed cache layer) degrades to "no finding" instead of an unhandled rejection. */
75587558
console.error(
75597559
JSON.stringify({
7560-
level: "warn",
7560+
level: "error",
75617561
event: "content_lane_deliverable_check_failed",
75627562
repository: args.repoFullName,
75637563
pullNumber: primaryIssueNumber,
@@ -9058,12 +9058,12 @@ async function maybePublishPrPublicSurface(
90589058
// Stamp the head SHA only after every required public surface for this repo completed. For gate-enabled repos,
90599059
// a comment/label without a finalized Orb gate check is incomplete and must stay repair-visible to the sweep.
90609060
await markPullRequestSurfacePublished(env, repoFullName, pr.number, advisory.headSha).catch((error) => {
9061-
console.error(JSON.stringify({ level: "warn", event: "surface_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
9061+
console.error(JSON.stringify({ level: "error", event: "surface_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
90629062
});
90639063
// #regate-churn: mark the AI review row for THIS head+fingerprint as durably published (a no-op when no fresh
90649064
// row was written this pass -- e.g. the frozen-reuse path above, or AI review off/skipped entirely).
90659065
await markAiReviewPublished(env, repoFullName, pr.number, advisory.headSha).catch((error) => {
9066-
console.error(JSON.stringify({ level: "warn", event: "ai_review_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
9066+
console.error(JSON.stringify({ level: "error", event: "ai_review_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
90679067
});
90689068
return gateEvaluation;
90699069
};
@@ -10374,7 +10374,7 @@ async function maybePublishPrPublicSurface(
1037410374
}).catch((error) => {
1037510375
console.error(
1037610376
JSON.stringify({
10377-
level: "warn",
10377+
level: "error",
1037810378
event: "gate_check_summary_upsert_failed",
1037910379
repoFullName,
1038010380
pullNumber: pr.number,
@@ -10466,7 +10466,7 @@ async function maybePublishPrPublicSurface(
1046610466
}).catch((error) => {
1046710467
console.error(
1046810468
JSON.stringify({
10469-
level: "warn",
10469+
level: "error",
1047010470
event: "gate_check_summary_upsert_failed",
1047110471
repoFullName,
1047210472
pullNumber: pr.number,
@@ -10512,7 +10512,7 @@ async function maybePublishPrPublicSurface(
1051210512
}).catch((error) => {
1051310513
console.error(
1051410514
JSON.stringify({
10515-
level: "warn",
10515+
level: "error",
1051610516
event: "gate_check_summary_upsert_failed",
1051710517
repoFullName,
1051810518
pullNumber: pr.number,
@@ -10554,7 +10554,7 @@ async function maybePublishPrPublicSurface(
1055410554
}).catch((error) => {
1055510555
console.error(
1055610556
JSON.stringify({
10557-
level: "warn",
10557+
level: "error",
1055810558
event: "gate_check_summary_upsert_failed",
1055910559
repoFullName,
1056010560
pullNumber: pr.number,

src/queue/slop-detection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export async function runAiSlopForAdvisory(
172172
} catch (error) {
173173
console.error(
174174
JSON.stringify({
175-
level: "warn",
175+
level: "error",
176176
event: "ai_slop_failed",
177177
repository: args.repoFullName,
178178
pullNumber: args.pr.number,
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { readFileSync } from "node:fs";
2+
import { join } from "node:path";
3+
import { describe, expect, it } from "vitest";
4+
5+
// #7806 — console.error sinks must not stamp level:"warn" (Sentry severity follows the explicit
6+
// level field over the sink default). Keep the three queue files consistent with the rest of
7+
// their console.error call sites.
8+
const QUEUE_FILES = [
9+
"src/queue/processors.ts",
10+
"src/queue/slop-detection.ts",
11+
"src/queue/ai-review-orchestration.ts",
12+
] as const;
13+
14+
function consoleErrorBlocks(source: string): string[] {
15+
const blocks: string[] = [];
16+
let i = 0;
17+
while (true) {
18+
const start = source.indexOf("console.error(", i);
19+
if (start < 0) break;
20+
let k = start + "console.error(".length;
21+
let depth = 1;
22+
while (k < source.length && depth > 0) {
23+
const ch = source[k]!;
24+
if (ch === "(") depth += 1;
25+
else if (ch === ")") depth -= 1;
26+
else if (ch === '"' || ch === "'" || ch === "`") {
27+
const quote = ch;
28+
k += 1;
29+
while (k < source.length) {
30+
if (source[k] === "\\") {
31+
k += 2;
32+
continue;
33+
}
34+
if (source[k] === quote) break;
35+
k += 1;
36+
}
37+
}
38+
k += 1;
39+
}
40+
blocks.push(source.slice(start, k));
41+
i = k;
42+
}
43+
return blocks;
44+
}
45+
46+
describe("queue console.error level matches the error sink (#7806)", () => {
47+
it("never stamps level:\"warn\" inside console.error payloads in the queue pipeline", () => {
48+
const mismatches: string[] = [];
49+
for (const rel of QUEUE_FILES) {
50+
const source = readFileSync(join(process.cwd(), rel), "utf8");
51+
for (const block of consoleErrorBlocks(source)) {
52+
if (block.includes('level: "warn"') || block.includes("level: 'warn'")) {
53+
mismatches.push(rel);
54+
}
55+
}
56+
}
57+
expect(mismatches).toEqual([]);
58+
});
59+
60+
it("keeps at least one representative console.error payload at level:\"error\"", () => {
61+
const source = readFileSync(join(process.cwd(), "src/queue/slop-detection.ts"), "utf8");
62+
expect(source).toMatch(/console\.error\(\s*JSON\.stringify\(\s*\{\s*level:\s*"error"/);
63+
expect(source).toContain('event: "ai_slop_failed"');
64+
});
65+
});

0 commit comments

Comments
 (0)