<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jvq on JVQ.net</title>
    <link>https://jvq.net/tags/jvq/</link>
    <description>Recent content in Jvq on JVQ.net</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 04 Nov 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://jvq.net/tags/jvq/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>jvq Flaky Now Takes Three Lines of YAML and Shows the Tests a Crash Skipped</title>
      <link>https://jvq.net/jvq-flaky-now-takes-three-lines-of-yaml-and-shows-the-tests-a-crash-skipped/</link>
      <pubDate>Wed, 04 Nov 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-flaky-now-takes-three-lines-of-yaml-and-shows-the-tests-a-crash-skipped/</guid>
      <description>&lt;p&gt;The flaky test gate in 0.7 worked, but setting it up in GitHub Actions meant copying fifteen lines of YAML: restore a cache, pick the right flag for pull requests, run the gate, save the cache, but only on the main branch. Most people who&amp;rsquo;d want it would read that block and decide to do it later.&lt;/p&gt;&#xA;&lt;p&gt;Version 0.8.0 puts all of that in the action:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;run&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;go test -json ./... &amp;gt; go-test.json || true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;just-very-quickly/jvq@v0.8.0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;with&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;flaky&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;go-test.json&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The action installs jvq and keeps the test history in the Actions cache. Pushes to your default branch add to it, and so do manual and scheduled runs there. Pull requests are judged against it without writing, so a branch full of half-finished work can&amp;rsquo;t teach the gate that a broken test is flaky. Each job of a matrix keeps its own history, because a test that fails on one Go version and passes on another isn&amp;rsquo;t flaky, it&amp;rsquo;s broken on one of them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Shrinks Its Flaky Test History 80 Times and Lets You Pin Tests In or Out of Quarantine</title>
      <link>https://jvq.net/jvq-shrinks-its-flaky-test-history-80-times-and-lets-you-pin-tests-in-or-out-of-quarantine/</link>
      <pubDate>Wed, 04 Nov 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-shrinks-its-flaky-test-history-80-times-and-lets-you-pin-tests-in-or-out-of-quarantine/</guid>
      <description>&lt;p&gt;The flaky test gate keeps one line per CI run, and through 0.8 that line spelled out every test&amp;rsquo;s name. Fine for a few hundred tests. For a suite of 2000 Go tests with long package paths, 200 runs came to 26.8 MB, and that file goes in and out of the Actions cache on every job.&lt;/p&gt;&#xA;&lt;p&gt;Version 0.9.0 writes each name once. The file starts and ends with the list of test names, and a run&amp;rsquo;s line says which numbers passed, failed or were skipped:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Set Up jvq Flaky With GitHub Actions and Retries in pytest and Go</title>
      <link>https://jvq.net/how-to-set-up-jvq-flaky-with-github-actions-and-retries-in-pytest-and-go/</link>
      <pubDate>Sat, 31 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/how-to-set-up-jvq-flaky-with-github-actions-and-retries-in-pytest-and-go/</guid>
      <description>&lt;p&gt;&lt;code&gt;jvq flaky&lt;/code&gt; needs two things from your CI: test results it can read, and a history file that survives from one run to the next. Everything else is optional. These are the setups we&amp;rsquo;d start with, each one run for real before it went on this page.&lt;/p&gt;&#xA;&lt;p&gt;They were tested with the released 0.7.0 binary on a small demo project: a pytest suite of four tests, one of which fails about one try in three, and a Go package with the same kind of test. That test fails at random, the way a test does that waits on a slow service. The outputs below are copied from those runs, and the script that made them is in &lt;a href=&#34;https://github.com/just-very-quickly/jvq/tree/main/test/results/case-studies/flaky/recipes&#34;&gt;test/results/case-studies/flaky/recipes&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Quarantines Flaky Tests So They Stop Blocking Merges</title>
      <link>https://jvq.net/jvq-quarantines-flaky-tests-so-they-stop-blocking-merges/</link>
      <pubDate>Sat, 31 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-quarantines-flaky-tests-so-they-stop-blocking-merges/</guid>
      <description>&lt;p&gt;Every team has a test like this. It checks out a cart, or uploads a file, or waits on a socket, and about one run in ten it fails for no reason anyone can find. The pull request goes red. Somebody clicks &amp;ldquo;re-run&amp;rdquo; and it goes green. After a few weeks everyone clicks re-run without reading the failure, and one day the failure is real.&lt;/p&gt;&#xA;&lt;p&gt;Version 0.7.0 adds a second gate to jvq for this. &lt;code&gt;jvq flaky&lt;/code&gt; reads your test results, keeps a small history across CI runs, and tells two kinds of failure apart: a test that fails on code that also passed it, and a test that fails because the code broke.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Replays 26 of Its Own CI Runs and Blocks a Windows Test Bug Four Pushes in a Row</title>
      <link>https://jvq.net/jvq-replays-26-of-its-own-ci-runs-and-blocks-a-windows-test-bug-four-pushes-in-a-row/</link>
      <pubDate>Sat, 31 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-replays-26-of-its-own-ci-runs-and-blocks-a-windows-test-bug-four-pushes-in-a-row/</guid>
      <description>&lt;p&gt;The fastest way to find out what a flaky test gate does with real failures is to give it some. jvq has its own CI history on GitHub: 26 pushes to main between October 18 and October 31, 2026, each tested on Linux, macOS and Windows, with a second run under the race detector on Linux. Eight of those 26 runs went red.&lt;/p&gt;&#xA;&lt;p&gt;So we fed that history to &lt;code&gt;jvq flaky&lt;/code&gt; 0.7.0, run by run, in the order it happened, with each run&amp;rsquo;s real commit. One history per platform and test step, as the reference asks. A test that fails on Windows and passes on Linux has a Windows problem, and mixing the two would hide it.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How jvq Holds Up Beside a Noisy Neighbour, on a Drifting Machine and With Python Scripts</title>
      <link>https://jvq.net/how-jvq-holds-up-beside-a-noisy-neighbour-on-a-drifting-machine-and-with-python-scripts/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/how-jvq-holds-up-beside-a-noisy-neighbour-on-a-drifting-machine-and-with-python-scripts/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://jvq.net/how-jvq-was-tested-with-hundreds-of-runs-where-the-right-answer-was-known/&#34;&gt;first round of tests&lt;/a&gt; ran jvq hundreds of times on a Go benchmark whose cost we set by hand. That showed how often it raises a false alarm and how often it catches a real slowdown on an ordinary machine. CI machines aren&amp;rsquo;t always ordinary, though. Version 0.2 adds three harder settings, each with a known right answer, recorded on a shared two-core cloud VM and on a four-core GitHub-hosted runner.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq 0.5 Keeps a History to Catch the Slowdown That Arrives One Small Merge at a Time</title>
      <link>https://jvq.net/jvq-0.5-keeps-a-history-to-catch-the-slowdown-that-arrives-one-small-merge-at-a-time/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-0.5-keeps-a-history-to-catch-the-slowdown-that-arrives-one-small-merge-at-a-time/</guid>
      <description>&lt;p&gt;A budget gate has a blind spot, and it&amp;rsquo;s built in. jvq judges each change against its base. A change that makes a benchmark 1% slower passes a 5% budget, and it should. So does the next one. Ten merges later the code is about 10% slower, and every check said pass.&lt;/p&gt;&#xA;&lt;p&gt;Version 0.5 keeps a history so that kind of creep can show. Each run on the default branch adds a line to a small file. &lt;code&gt;jvq history&lt;/code&gt; reads it back: how far each benchmark has moved in all, with an interval, how many runs called it a regression, and a row of blocks with its change run by run.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Blocks a Go Logging Change That Added Two Allocations to Every Request</title>
      <link>https://jvq.net/jvq-blocks-a-go-logging-change-that-added-two-allocations-to-every-request/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-blocks-a-go-logging-change-that-added-two-allocations-to-every-request/</guid>
      <description>&lt;p&gt;An access logger writes one JSON line per request. In Go, the usual way to make that cheap is to append into a buffer the caller owns: no &lt;code&gt;fmt&lt;/code&gt;, no &lt;code&gt;encoding/json&lt;/code&gt;, no strings built along the way. Done right, the benchmark says 0 allocs/op, and the garbage collector never hears about the logger at all.&lt;/p&gt;&#xA;&lt;p&gt;That property is easy to lose and hard to notice. Time per call wanders by several percent from run to run on a CI machine. An allocation count doesn&amp;rsquo;t wander. That&amp;rsquo;s why jvq compares allocations exactly, and why their budget can be an amount, here 0, instead of a percentage. This worked example is a small Go package set up to show it, with two real commits run through jvq 0.5.0 on a two-core cloud VM.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Catches a Python Cleanup That Made URL Parsing Nearly Five Times Slower</title>
      <link>https://jvq.net/jvq-catches-a-python-cleanup-that-made-url-parsing-nearly-five-times-slower/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-catches-a-python-cleanup-that-made-url-parsing-nearly-five-times-slower/</guid>
      <description>&lt;p&gt;A log pipeline pulls query parameters out of request paths, millions of times a day. The function that does it is eight lines of hand-written splitting. It&amp;rsquo;s fast, and it has a bug everyone has learned to live with: &lt;code&gt;%20&lt;/code&gt; and &lt;code&gt;+&lt;/code&gt; come through undecoded.&lt;/p&gt;&#xA;&lt;p&gt;So someone opens a pull request that fixes it the proper way, with the standard library. Two lines replace eight. The review is easy to approve. This is a worked example we set up to show what jvq does with a change like that: a small repository with a pytest-benchmark suite, four real commits, and jvq 0.5.0 run on each one on a two-core cloud VM.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Flags an Update Check That Made a Go Command-Line Tool Nearly Four Times Bigger</title>
      <link>https://jvq.net/jvq-flags-an-update-check-that-made-a-go-command-line-tool-nearly-four-times-bigger/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-flags-an-update-check-that-made-a-go-command-line-tool-nearly-four-times-bigger/</guid>
      <description>&lt;p&gt;Some tools are judged by their size. A small binary that gets copied onto every build agent, baked into container images, or downloaded at the start of each CI job pays for every megabyte many times a day. Nobody looks at the size in review, because the diff doesn&amp;rsquo;t show it.&lt;/p&gt;&#xA;&lt;p&gt;jvq can gate the size of files your build makes, next to the timings. This worked example is a small Go command-line tool, &lt;code&gt;lvl&lt;/code&gt;, that counts log levels in JSON Lines files. Two real commits were run through jvq 0.5.0 on a two-core cloud VM.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Now Gates Benchmarks in Any Language, by Timing a Command or Reading a Few Lines of JSON</title>
      <link>https://jvq.net/jvq-now-gates-benchmarks-in-any-language-by-timing-a-command-or-reading-a-few-lines-of-json/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-now-gates-benchmarks-in-any-language-by-timing-a-command-or-reading-a-few-lines-of-json/</guid>
      <description>&lt;p&gt;The first jvq release read one thing: the output of Go&amp;rsquo;s &lt;code&gt;go test -bench&lt;/code&gt;. That covered Go projects and nothing else. Version 0.2 drops the limit. If your benchmark is a Python script, a Node program, a shell loop or a compiled binary in any language, jvq can now gate it.&lt;/p&gt;&#xA;&lt;p&gt;There are two new ways in. The &lt;code&gt;time&lt;/code&gt; adapter times the whole command, from start to exit, so there&amp;rsquo;s nothing to change in your code. The &lt;code&gt;json&lt;/code&gt; adapter reads results your benchmark prints, one per line, with a name, a unit and a value. Pick one with a line in jvq.toml or &lt;code&gt;-adapter&lt;/code&gt; on the command line.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Now Gates GitLab Merge Requests, With a Ready Template and a JUnit Report</title>
      <link>https://jvq.net/jvq-now-gates-gitlab-merge-requests-with-a-ready-template-and-a-junit-report/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-now-gates-gitlab-merge-requests-with-a-ready-template-and-a-junit-report/</guid>
      <description>&lt;p&gt;Until now jvq came with a GitHub Action and a line in the README saying GitLab works the same way. It did, if you worked out the base commit, the clone depth and the download yourself. Version 0.4 does that part for you.&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s a ready job to include, jvq reads GitLab&amp;rsquo;s own merge request variables to pick the base, and a new JUnit report puts the result in the merge request&amp;rsquo;s test summary, next to your other tests.&lt;/p&gt;</description>
    </item>
    <item>
      <title>jvq Now Reads criterion, Google Benchmark, pytest-benchmark and vitest as They Are, and Gates File Sizes</title>
      <link>https://jvq.net/jvq-now-reads-criterion-google-benchmark-pytest-benchmark-and-vitest-as-they-are-and-gates-file-sizes/</link>
      <pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/jvq-now-reads-criterion-google-benchmark-pytest-benchmark-and-vitest-as-they-are-and-gates-file-sizes/</guid>
      <description>&lt;p&gt;Version 0.2 let jvq gate a benchmark in any language, by timing the whole command or reading a few lines of JSON. That still meant a little glue for projects that already have a benchmark harness. Version 0.3 removes the glue for four of the most used ones. Point jvq at the harness and it reads the harness&amp;rsquo;s own output.&lt;/p&gt;&#xA;&lt;p&gt;It also adds a second kind of budget. Besides time, bytes and allocations, jvq can now fail a pull request that makes a file it builds bigger than it should be.&lt;/p&gt;</description>
    </item>
    <item>
      <title>First jvq Release Fails Pull Requests That Make Go Benchmarks Slower Than Their Budget</title>
      <link>https://jvq.net/first-jvq-release-fails-pull-requests-that-make-go-benchmarks-slower-than-their-budget/</link>
      <pubDate>Sun, 18 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/first-jvq-release-fails-pull-requests-that-make-go-benchmarks-slower-than-their-budget/</guid>
      <description>&lt;p&gt;Most slowdowns get in one pull request at a time. An extra allocation in a loop, a string copied where a slice would do, a log call on the hot path. Each costs a few percent, each passes review, and a month later the service is 30% slower and nobody can say which change did it.&lt;/p&gt;&#xA;&lt;p&gt;jvq 0.1 is a check you put in CI to stop that. You give it a benchmark command and a budget, such as 5% slower at most. On every pull request it runs your benchmarks on the base branch and on the change, on the same runner, taking turns, and fails the build when the change is clearly over budget.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How jvq Was Tested With Hundreds of Runs Where the Right Answer Was Known</title>
      <link>https://jvq.net/how-jvq-was-tested-with-hundreds-of-runs-where-the-right-answer-was-known/</link>
      <pubDate>Sun, 18 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/how-jvq-was-tested-with-hundreds-of-runs-where-the-right-answer-was-known/</guid>
      <description>&lt;p&gt;A gate that blocks merges has two ways to fail. It can cry wolf, flagging changes that did nothing, until people stop trusting it. Or it can sleep through a real slowdown. The only way to know how often jvq does either is to run it many times on changes where you already know the answer, and count.&lt;/p&gt;&#xA;&lt;p&gt;So that&amp;rsquo;s what its test suite does. A fixture benchmark runs a CPU loop whose length is set by a constant. One commit uses the base length. The next adds a set amount of work, 2% more, 10% more, 50% more, or changes only a comment. Then the real jvq binary runs on that repository, start to finish, with its default settings: two git worktrees, a build for each side, a warm-up, 10 rounds taking turns, more rounds while undecided, and the 5% budget.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Performance Budgets in CI Only Work When Base and Head Run Side by Side</title>
      <link>https://jvq.net/performance-budgets-in-ci-only-work-when-base-and-head-run-side-by-side/</link>
      <pubDate>Sun, 18 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/performance-budgets-in-ci-only-work-when-base-and-head-run-side-by-side/</guid>
      <description>&lt;p&gt;A performance budget is a promise written into the pipeline: this change may make the code at most 5% slower, and if it&amp;rsquo;s worse, the build fails. Tests already guard what the code does. A budget guards how fast it does it.&lt;/p&gt;&#xA;&lt;p&gt;The idea is old and simple. Making it work on ordinary CI machines is the hard part, because those machines are noisy. On the shared two-core cloud machine where jvq was tested, the very same benchmark binary, run 40 times in a row, spread by 8.9% from one run to the next. A budget of 5% sits well inside that noise, so a naive check can&amp;rsquo;t tell a real slowdown from the runner having a bad minute.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Why the Benchmark Gate Is Called jvq for Just Very Quickly</title>
      <link>https://jvq.net/why-the-benchmark-gate-is-called-jvq-for-just-very-quickly/</link>
      <pubDate>Sun, 18 Oct 2026 00:00:00 +0000</pubDate>
      <guid>https://jvq.net/why-the-benchmark-gate-is-called-jvq-for-just-very-quickly/</guid>
      <description>&lt;p&gt;jvq stands for just very quickly. It&amp;rsquo;s what you say when someone asks whether a change will slow things down. &amp;ldquo;It only adds a check, it&amp;rsquo;ll run just very quickly.&amp;rdquo; Most of the time that&amp;rsquo;s true. Sometimes it isn&amp;rsquo;t, and nobody finds out until the dashboards turn red a month later.&lt;/p&gt;&#xA;&lt;p&gt;The tool exists for the second case. It takes the words at face value and checks them, on every pull request, against the code before the change.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
