What happened
A Google Developers Blog post by the lead of Google's agent skills program describes a bug-hunting that pairs the Gemini 4 Argon model with the Z3 constraint solver to find crash-inducing Go code that fuzzing misses. The author compiled target functions with Go's bounds-check debugging flags, fed the source and disassembly to Argon, and had the model write Z3 constraint models for every panic trap the compiler could not eliminate. Z3 then solved for concrete crashing inputs, which go test replayed against the real functions. The pipeline caught all three deliberately planted parser bugs and three latent bugs in skill-lint, the author's Go CLI for validating agent skill files.
The author, who leads Google's agent skills program of 175 skills, built the to harden skill-lint, a standalone Go CLI that checks SKILL.md files and applies LLM-generated line edits. The method starts from Go's SSA prove pass, which strips out bounds checks it can prove safe and leaves explicit runtime.panicBounds traps in the machine code. The author compiled targets with GOOS=linux GOARCH=riscv64 and the ssa/check_bce/debug=1 flag, which logs every surviving bounds check, then passed both Go source and disassembly to Gemini 4 Argon. The model returned a Z3 script modeling the path to each surviving trap plus a patched function whenever it flagged a bug. Z3 checked satisfiability in milliseconds; Argon's translation dominated runtime at roughly a minute per function. Every sat answer came with concrete bytes that go test ran against the real function, so every confirmed crash was real regardless of whether the model's translation was sound.
On planted bugs, the caught all three. In ParseTwoChunkFrame, a uint8 addition wrapped at 256 before a length guard, and Z3 produced a 59-byte counterexample with hdrLen = 48 and bodyLen = 236, where the wrapped sum of 28 passed the guard but the slice reached index 288 and panicked. The post states 19.4 percent of possible header pairs trigger this crash, yet a 3-second fuzz run and three 60-second runs all missed it. The reason: Go checks slices against capacity, and in a probe of 386,741 fuzz calls, 89 percent of inputs were views into a shared roughly 100 MB buffer and only 0.07 percent had cap equal to len. ExtractQuotedToken had the same blind spot; Z3 caught it with the 2-byte input of a quote and a trailing backslash. After the author clipped capacity to length with a full slice expression, the fuzzer crashed both targets in all three runs, with medians of 0.28 and 0.17 seconds. A third planted bug, ParseMagicPacket, served as a control that the fuzzer found either way.
Pointing the at skill-lint itself, the author extracted pure functions and slice helpers from file-reading code, leaving CLI flags, network calls, and file I/O to standard fuzzing and race detection, because the 28 MB binary links 32,321 symbols. Of five functions tested, two scanners returned unsat, including a CRLF line splitter with six surviving bounds checks, and three had real bugs. The sharpest, in ApplyReplacementChunks, was that sorting edit chunks by StartLine does not prevent overlap; a second chunk spanning lines 2 through 4 of a file shrunk to 3 lines evaluated lines[4:] and panicked in the extracted helper, while the shipped code turned it into a misleading range error or silently overwrote the earlier edit. The other two were accounting errors: a local fixer checked line numbers before deletions shrank the slice, and a packer reserved a flat 100 bytes for a roughly 70-byte wrapper plus file path, overshooting a 2 MB context budget when a path exceeded about 30 bytes. The author reran the skill-lint targets with all comments stripped and Argon still caught all three bugs and returned unsat on the two scanners and all three patches.
The post situates the work against a recent Anthropic post using frontier AI models to write machine-checked Rocq proofs for C and C++ libraries under OSS-Fuzz. The author's approach trades theorem proving for SMT: without a full semantic model it cannot prove correctness, but across all six buggy functions the first sat assignment Z3 returned triggered a real panic in go test with no false positives to filter. The author notes the target must include its own entry-point guards, or Z3 will invent inputs violating caller-enforced preconditions.
Source details: developers.googleblog.com
Why it matters
The post is a concrete, reproducible demonstration that an LLM plus an off-the-shelf SMT solver can deliver much of the bug-finding value of formal verification at a small fraction of the effort, and it documents a specific, measurable blind spot in Go's standard fuzzing tool that practitioners can act on immediately. The author shows that go test -fuzz missed two planted crashes because Go checks slice expressions against capacity rather than length, and 89 percent of fuzz inputs in a 10-second probe were views into a shared buffer with spare capacity, so overrun bugs silently returned wrong bytes instead of panicking. A one-line fix, clipping slice capacity to length, let the fuzzer catch both bugs in under a third of a second. The work also explains the method's honest limits: an LLM-written solver model is not a sound proof, an unsat result only means maybe correct, and single-threaded models cannot see data races or deadlocks.
The post gives a measured, falsifiable comparison rather than a claim: unseeded go test -fuzz on Go 1.27.3, run with a fresh fuzz cache, missed two of three planted crashes across a 3-second run and three 60-second runs, while the Argon-plus-Z3 caught all three and produced concrete reproducers.
The documented capacity-versus-length blind spot is independently actionable even for developers who never touch a solver: clipping slice capacity to length with a full slice expression fixed the fuzzer's misses, and the author recommends fuzzing pure helpers this way as the default for most Go code.
The method is honest about its limits, which is rare in AI tooling write-ups: an LLM-written solver model is not a sound proof system, unsat only means maybe correct, single-threaded models cannot see data races or deadlocks, and concurrent code still belongs with the race detector and Go 1.27's goroutine leak profiles.
It shows a concrete division of labor between an LLM and a solver: Argon's translation of Go source and assembly into Z3 constraints, at about a minute per function, replaced what would otherwise be manual constraint writing, while Z3 and go test provided the verification step.
The results are the author's own claims from a primary-source blog post, not independently verified third-party results; the planted-bug and skill-lint findings have not been corroborated outside this post.
Interactive Mechanism: How It Actually Works
Explore the underlying technology behind this development interactively.
crm_get_transaction(id='4092').An agent must create a draft calendar event for Tuesday at 2 p.m. Which evidence would establish the requested result?
What to watch next
Watch whether this compiler-traps-plus-solver workflow gets packaged into standard Go tooling or coding agents, and whether the capacity-clipping insight changes fuzzing guidance in Go's own testing documentation. The author explicitly invites practitioners experimenting with solvers and coding agents on Go to compare notes, which could surface follow-up results on larger codebases. It is also worth tracking how this SMT-based approach compares with the interactive theorem-proving route Anthropic recently demonstrated for C and C++, and whether Gemini 4 Argon becomes generally available for others to replicate the .
Whether the capacity-clipping insight propagates into Go's official fuzzing guidance or tooling, since the post quantifies the problem with a 386,741-call probe showing only 0.07 percent of inputs had cap equal to len.
Whether solver-assisted bug hunting gets integrated into coding agents or standard Go developer tooling, which the author suggests is the practical next step for traps that survive both the compiler's range prover and a quick fuzz run.
How this SMT approach scales relative to Anthropic's whole-binary Rocq setup, which the post notes operated under a 64 MB budget and for which a Go 1.27 runtime overlay exists in theorem-labs/oss-verify.
Whether Gemini 4 Argon's availability widens so others can replicate the ; the post does not document public access conditions or pricing for the model, which remains unknown.