8 views
This guide covers CI failure triage bots with production-focused examples and trade-offs.
Not every red X deserves a page. A triage bot that cannot tell flake from regression will either spam on-call or silently rerun real breakages until the deploy train derails. Classify failures with signatures from history, auto-rerun only the flake class, and escalate novel signatures hard.⚡ TL;DR: Fingerprint failures (test id + error class + stack top frames). Train/maintain a classifier on labeled history:flake|regression|infra|novel. Auto-rerun flakes with a budget; never auto-rerunregressionornovel. Page on novel post-deploy signatures. Pair with AI Test Generation: Property Tests and OpenTelemetry for LLMs for correlating CI with prod.
Fingerprints beat raw log dumps — CI failure triage bots
typescript
✅ Stable across line-number jitter and runner paths.import { createHash } from "node:crypto";
export function fingerprint(fail: {
testId: string;
message: string;
stack: string[];
}): string {
const top = fail.stack.slice(0, 3).map(normalizeFrame).join("|");
const msgClass = fail.message.replace(/\d+/g, "N").replace(/0x[0-9a-f]+/gi, "HEX");
return createHash("sha256")
.update(`${fail.testId}::${msgClass}::${top}`)
.digest("hex")
.slice(0, 16);
}
function normalizeFrame(f: string) {
return f.replace(/:\d+:\d+/g, ":L:C").replace(/\/home\/runner\/.*/g, "REPO");
}
❌ Hashing the entire log (unique every time → everything looks novel).
Classifier with an explicit novel bucket
typescript
Use historical CI data; an LLM can narrate but must not be the only voter on auto-rerun. Ground narratives like LLM Incident Runbooks.
type Label = "flake" | "regression" | "infra" | "novel";
export async function classify(fp: string, ctx: {
seenCount90d: number;
flakeRatio90d: number;
firstSeenAfterDeploy: boolean;
matchedInfraSignature: boolean;
}): Promise<Label> {
if (ctx.matchedInfraSignature) return "infra";
if (ctx.seenCount90d === 0) return "novel";
if (ctx.flakeRatio90d >= 0.6 && !ctx.firstSeenAfterDeploy) return "flake";
if (ctx.firstSeenAfterDeploy && ctx.flakeRatio90d < 0.2) return "regression";
// LLM assist for ambiguous mid-band — optional, never sole authority
return "novel"; // fail closed toward human eyes
}
Actions by class
yaml
flake:
action: rerun_job
max_reruns: 1
notify: silent_metric
regression:
action: block_merge
notify: pr_comment + slack_team
infra:
action: rerun_on_new_runner
notify: platform_oncall (if burst)
novel:
action: block_merge
notify: page_deploying_team
require: human_label_within_24h
typescript
Quarantine with a hard fix SLA — do not let flakes rot coverage forever.
export async function handleFailure(label: Label, job: Job) {
switch (label) {
case "flake":
if (job.reruns < 1) return rerun(job);
return quarantineTest(job.testId, { slaHours: 72 });
case "regression":
return blockMerge(job.pr, `regression_fingerprint=${job.fp}`);
case "infra":
return rerun(job, { runnerLabel: "fresh" });
case "novel":
await page(job.deployingTeam, job);
return blockMerge(job.pr, `novel_fingerprint=${job.fp}`);
}
}
Feedback loop so the classifier stays honest
| Signal | Use |
|---|---|
| Human relabel in Slack | Training gold |
| Rerun then green without code change | Evidence for flake |
| Rerun then same fingerprint | Evidence for regression |
| Post-merge incident tied to ignored fingerprint | Severity bump |
Closing checklist
- [ ] Fingerprints from test id + normalized message + top stack frames
- [ ] Labels include explicit
novel; unknown ≠ flake - [ ] Auto-rerun only for
flake(budget 1) and controlledinfra - [ ]
regressionandnovelblock merge and notify humans - [ ] Quarantine SLA for repeated flakes; metrics on misclassification
- [ ] Post-deploy novel signatures page the deploying team
Related reading
- AI Test Generation: Property Tests That Catch Race Conditions
- LLM Incident Runbooks: Ground On-Call Answers in CloudWatch Signals
- Semantic Diff Review: AI That Flags Behavioral Drift Only
- OpenTelemetry for LLMs: Trace Prompt Latency Across Microservices
Related: Day 55: Swarm Failure Modes · Lambda Timeouts, Retries, and DLQs: Idempotent Failure Handling · Lambda Multi-Arch Builds: arm64 CI Matrices That Actually Ship
Watch: 100 Days of AI on YouTube
Short videos from CheatCoders, one AI engineering topic per day.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Claude Code vs Cursor vs GitHub Copilot: Choose by Workflow, and Set Up One Repo That Works With All Three
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- Css Animation Performance: Performance-Optimized Motion for Modern UIs
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Runtime Config for Coding Agents
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena for Coding Agents: Query Tool Audit Logs and Eval Traces on S3 Without a Warehouse
- AWS Batch for Coding Agents: Parallel Overnight PR Reviews and Long-Running Jobs Without Lambda Timeouts
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.

Pingback: Lambda Event Source Filters: Drop Noise Before Paying for Invokes - CheatCoders