Groundhog 整理重複 CI 故障並找回既有解決記錄
Groundhog: less déjà vu in CI
Groundhog 是作者自建的本機優先 CI 故障筆記本,可匯入 JUnit 報告、分組重複症狀,並找回先前記錄的解決方案,即使錯誤措辭有所不同。它以 MiniLM 語義檢索搭配棄答門檻;在包含 20 個記憶、40 個已知變體及 20 個相似異因故障的合成壓力測試中,正確記憶排名第一為 39/40,建議正確率為 64%,低於 Jaccard 的 70%。
This is a submission for the Hacktoberfest Open-Source AI Challenge: Week 3.
What I Built
A red build can mean a new problem. It can also mean finding the answer you already found last Tuesday.
I built Groundhog, a local-first notebook for recurring CI failures. Import a JUnit report, group repeated symptoms, and retrieve a resolution you recorded before, even when the error's wording changes. It keeps the current failure beside the historical symptom, fix note, and supporting evidence.
For Slow and Steady, the goal is to stop digging through old logs for the same resolution. Record it once, find it again, and check whether it fits. Groundhog leaves code changes and reruns to you.
Demo
Try Groundhog in your browser. No account or API key is needed.
The supplied examples walk through a recurring CI failure without requiring private logs:
- Open the synthetic run: 12 failures become five exact symptom groups, with every occurrence retained.
- Load the optional model and inspect a related resolution alongside the current evidence.
- Set aside a poor suggestion without suppressing its failure.
- After testing your own resolution, save the note and evidence. Replay the report to retrieve it again, or export the notebook for the CLI.
Code
Source code and setup · Evaluation and per-case evidence
Original code is MIT-licensed. Upstream components retain their own licenses and credits.
How I Built It
The static JavaScript app has two jobs:
- Exact grouping: normalize run-specific noise, then group identical symptoms. Assertion values and error codes remain significant. This works without AI.
- Semantic retrieval: encode symptoms with the pinned q8 all-MiniLM-L6-v2 model, then compare its 384-dimensional vectors with stored incident symptoms. Fix text is never used to rank candidates.
Transformers.js and ONNX Runtime Web run the model in a worker. A candidate needs both a minimum similarity and a gap from the runner-up. Otherwise, the app abstains; scores are not probabilities.
Keep the evidence the model needs
Two long-log probes exposed a practical bug. One ended in ENOSPC; the other in ENOTFOUND. Both began with enough identical setup chatter to fill MiniLM's 256-token window, so their embeddings were identical. The model never saw the distinction.
I added diagnostic-lines-v1, a deterministic excerpt selector that favors error codes, exceptions, and assertion lines over repeated debug output. It retains both late diagnostics in those probes and marks omissions. The UI shows the excerpt and line numbers within the normalized symptom, not raw JUnit file lines. Original evidence remains available separately.
The post-fix regression ranked the correct memory first for both probes; only the DNS case passed the existing suggestion gates. Selection is still lossy, and excerpts can exceed the token limit. The original failed run is retained. This rerun uses inspected cases, not fresh held-out data.
Compare the model with simpler tools
The gates were calibrated on 13 cases against three memories. The original held-out set gave lexical and semantic retrieval identical known-case ranking, so I expanded the test without retuning either policy.
The larger stress test has 20 memories, 40 known variants, and 20 similar-looking failures with different causes. Queries pass through generated JUnit, the actual parser, and grouping. These first-run totals were unchanged by the post-fix regression:
| Method | Correct first-ranked memory, of 40 | Correct suggestions, of 40 | Wrong suggestions on unfamiliar cases, of 20 |
|---|---|---|---|
| Normalized exact match | 0 | 0 | 0 |
| Token-set Jaccard | 36 | 21 | 9 |
| MiniLM + abstention | 39 | 16 | 9 |
MiniLM ranked better here, but its suggestions were 64% correct, versus 70% for Jaccard. One wrong suggestion linked an unexpired JWT with the wrong audience to an expired-token resolution. Twenty separate exact-replay controls passed.
All cases and labels are authored synthetic data. The percentages describe this deliberately difficult case mix, not production accuracy. Suggestions still need evidence review.
Checks you can rerun
The final application-source CI run passed: 110 unit, adversarial, and lifecycle tests; 11 DOM-stub UI checks; a production build; actual native and WASM model checks; and frozen-policy regressions. The tested source commit matches the deployed application files.
Native and CPU-WASM-under-Node regressions produced identical accept/reject decisions. The separate interactive Chromium checks exercised real model loading, replay, dismissal, persistence, and export/restore. Cold-cache performance, offline operation, and other browsers remain unverified.
With Node 24:
npm ci --ignore-scripts
npm test
npm run test:ui-state
npm run test:model
npm run test:wasm
npm run evaluate -- --verify
node tools/stress-evaluate.mjs --verify
node tools/stress-evaluate.mjs --verify-wasm
npm run build
Why Does Open Innovation Matter?
MiniLM's Apache-2.0 weights, Apache-2.0 Transformers.js, and MIT-licensed ONNX Runtime allow local inference without an inference account, API key, or per-query service bill. First-load assets need internet: roughly 23 MB of weights and 14.3 MB of WASM, plus tokenizer and app files. The application does not send report text to a hosted inference API.
You can inspect the model revision, normalization rules, thresholds, and failed cases; replace the encoder; or keep a lexical baseline if it suits your reports better. The notebook exports versioned JSON, so its contents are not tied to a hosted service.
The Lazy Payoff
The browser examples are hand-authored. A separate fixture generator actually raises and captures 18 controlled Python exceptions; the CLI groups those into 12 exact symptoms. Run npm run fixtures:generate, then node tools/groundhog.mjs tests/fixtures/generated/captured.xml.
These are grouping counts, not measured hours saved.
來源:DEV Community · dev.to

