Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/queue/ai-review-orchestration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ export async function runAiReviewForAdvisory(
} catch (error) {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "ai_review_failed",
repository: args.repoFullName,
pullNumber: args.pr.number,
Expand Down
44 changes: 22 additions & 22 deletions src/queue/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ export async function buildContributorDecisionPacks(
/* v8 ignore next -- defensive per-login isolation; the log-and-continue path is not exercised in tests */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "decision_pack_login_failed",
login: contributorLogin,
error: errorMessage(error),
Expand Down Expand Up @@ -1474,7 +1474,7 @@ export async function sweepRepoRegate(
).catch((error) => {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "sweep_mark_regated_failed",
repository: repoFullName,
error: errorMessage(error),
Expand Down Expand Up @@ -1775,7 +1775,7 @@ export async function sweepRepoBacklogConvergence(
).catch((error) => {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "backlog_convergence_mark_regated_failed",
repository: repoFullName,
error: errorMessage(error),
Expand Down Expand Up @@ -1919,7 +1919,7 @@ export async function regatePullRequest(
}
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "sweep_rereview_failed",
deliveryId,
repository: repoFullName,
Expand Down Expand Up @@ -3584,7 +3584,7 @@ export async function reReviewStoredPullRequest(
if (isGitHubRateLimitedError(error) || isRetryableJobError(error)) throw error;
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "pr_public_surface_failed",
deliveryId,
repository: repoFullName,
Expand Down Expand Up @@ -3618,7 +3618,7 @@ export async function reReviewStoredPullRequest(
).catch((error) => {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "agent_maintenance_failed",
deliveryId,
repository: repoFullName,
Expand Down Expand Up @@ -5139,7 +5139,7 @@ async function processContributorEvidenceLogins(
/* v8 ignore next -- defensive per-login isolation; the log-and-continue path is not exercised in tests */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "contributor_evidence_login_failed",
login: contributorLogin,
error: errorMessage(error),
Expand Down Expand Up @@ -6388,7 +6388,7 @@ async function handlePullRequestWebhookEvent(
if (isGitHubRateLimitedError(error) || isRetryableJobError(error)) throw error;
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "pr_public_surface_failed",
deliveryId,
repository: payload.repository?.full_name,
Expand Down Expand Up @@ -6426,7 +6426,7 @@ async function handlePullRequestWebhookEvent(
/* v8 ignore next -- best-effort: auto-maintain failures are logged, never surfaced to the gate. */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "agent_maintenance_failed",
deliveryId,
repository: repoFullName,
Expand Down Expand Up @@ -6457,7 +6457,7 @@ async function handlePullRequestWebhookEvent(
/* v8 ignore next -- best-effort: a reputation-record failure is logged, never surfaced to the gate. */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "reputation_record_failed",
deliveryId,
repository: repoFullName,
Expand All @@ -6483,7 +6483,7 @@ async function handlePullRequestWebhookEvent(
/* v8 ignore next -- best-effort: a RAG re-index enqueue failure is logged, never surfaced to the gate. */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "rag_reindex_enqueue_failed",
deliveryId,
repository: repoFullName,
Expand All @@ -6508,7 +6508,7 @@ async function handlePullRequestWebhookEvent(
/* v8 ignore next -- best-effort: a sibling re-gate enqueue failure is logged, never surfaced to the gate. */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "sibling_regate_enqueue_failed",
deliveryId,
repository: repoFullName,
Expand Down Expand Up @@ -6612,7 +6612,7 @@ async function handleIssueWebhookEvent(
/* v8 ignore next -- best-effort: an issue-cap enforcement failure is logged, never surfaced to the webhook. */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "contributor_issue_cap_failed",
deliveryId,
repository: payload.repository?.full_name,
Expand Down Expand Up @@ -7013,7 +7013,7 @@ async function resolvePullRequestFilesForReview(
/* v8 ignore next -- fail-safe: an inline fetch failure degrades to the empty stored rows (byte-identical to pre-fix). */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "review_files_inline_fetch_failed",
repository: args.repoFullName,
pullNumber: args.pullNumber,
Expand Down Expand Up @@ -7479,7 +7479,7 @@ export async function runLinkedIssueSatisfactionForAdvisory(
} catch (error) {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "linked_issue_satisfaction_failed",
repository: args.repoFullName,
pullNumber: args.pr.number,
Expand Down Expand Up @@ -7557,7 +7557,7 @@ export async function runContentLaneDeliverableCheckForAdvisory(
* calls (e.g. a DB-backed cache layer) degrades to "no finding" instead of an unhandled rejection. */
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "content_lane_deliverable_check_failed",
repository: args.repoFullName,
pullNumber: primaryIssueNumber,
Expand Down Expand Up @@ -9058,12 +9058,12 @@ async function maybePublishPrPublicSurface(
// Stamp the head SHA only after every required public surface for this repo completed. For gate-enabled repos,
// a comment/label without a finalized Orb gate check is incomplete and must stay repair-visible to the sweep.
await markPullRequestSurfacePublished(env, repoFullName, pr.number, advisory.headSha).catch((error) => {
console.error(JSON.stringify({ level: "warn", event: "surface_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
console.error(JSON.stringify({ level: "error", event: "surface_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
});
// #regate-churn: mark the AI review row for THIS head+fingerprint as durably published (a no-op when no fresh
// row was written this pass -- e.g. the frozen-reuse path above, or AI review off/skipped entirely).
await markAiReviewPublished(env, repoFullName, pr.number, advisory.headSha).catch((error) => {
console.error(JSON.stringify({ level: "warn", event: "ai_review_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
console.error(JSON.stringify({ level: "error", event: "ai_review_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
});
return gateEvaluation;
};
Expand Down Expand Up @@ -10374,7 +10374,7 @@ async function maybePublishPrPublicSurface(
}).catch((error) => {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "gate_check_summary_upsert_failed",
repoFullName,
pullNumber: pr.number,
Expand Down Expand Up @@ -10466,7 +10466,7 @@ async function maybePublishPrPublicSurface(
}).catch((error) => {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "gate_check_summary_upsert_failed",
repoFullName,
pullNumber: pr.number,
Expand Down Expand Up @@ -10512,7 +10512,7 @@ async function maybePublishPrPublicSurface(
}).catch((error) => {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "gate_check_summary_upsert_failed",
repoFullName,
pullNumber: pr.number,
Expand Down Expand Up @@ -10554,7 +10554,7 @@ async function maybePublishPrPublicSurface(
}).catch((error) => {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "gate_check_summary_upsert_failed",
repoFullName,
pullNumber: pr.number,
Expand Down
2 changes: 1 addition & 1 deletion src/queue/slop-detection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export async function runAiSlopForAdvisory(
} catch (error) {
console.error(
JSON.stringify({
level: "warn",
level: "error",
event: "ai_slop_failed",
repository: args.repoFullName,
pullNumber: args.pr.number,
Expand Down
65 changes: 65 additions & 0 deletions test/unit/queue-console-error-level.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";

// #7806 — console.error sinks must not stamp level:"warn" (Sentry severity follows the explicit
// level field over the sink default). Keep the three queue files consistent with the rest of
// their console.error call sites.
const QUEUE_FILES = [
"src/queue/processors.ts",
"src/queue/slop-detection.ts",
"src/queue/ai-review-orchestration.ts",
] as const;

function consoleErrorBlocks(source: string): string[] {
const blocks: string[] = [];
let i = 0;
while (true) {
const start = source.indexOf("console.error(", i);
if (start < 0) break;
let k = start + "console.error(".length;
let depth = 1;
while (k < source.length && depth > 0) {
const ch = source[k]!;
if (ch === "(") depth += 1;
else if (ch === ")") depth -= 1;
else if (ch === '"' || ch === "'" || ch === "`") {
const quote = ch;
k += 1;
while (k < source.length) {
if (source[k] === "\\") {
k += 2;
continue;
}
if (source[k] === quote) break;
k += 1;
}
}
k += 1;
}
blocks.push(source.slice(start, k));
i = k;
}
return blocks;
}

describe("queue console.error level matches the error sink (#7806)", () => {
it("never stamps level:\"warn\" inside console.error payloads in the queue pipeline", () => {
const mismatches: string[] = [];
for (const rel of QUEUE_FILES) {
const source = readFileSync(join(process.cwd(), rel), "utf8");
for (const block of consoleErrorBlocks(source)) {
if (block.includes('level: "warn"') || block.includes("level: 'warn'")) {
mismatches.push(rel);
}
}
}
expect(mismatches).toEqual([]);
});

it("keeps at least one representative console.error payload at level:\"error\"", () => {
const source = readFileSync(join(process.cwd(), "src/queue/slop-detection.ts"), "utf8");
expect(source).toMatch(/console\.error\(\s*JSON\.stringify\(\s*\{\s*level:\s*"error"/);
expect(source).toContain('event: "ai_slop_failed"');
});
});