---
title: "The Log Filter That Broke Release Verification"
canonical: https://dxdev.com/blog/2026-09-26_rtk-compression-breaks-verification/
datePublished: 2026-07-30
---
Three hotfix tags went out on one day, and on that same day I rewrote the global rules for `rtk`, the output compressor I put in front of shell commands to save tokens. The rewrite happened because its `git log` filter had misled release verification. This is what the filter did and why it was the wrong place to save tokens.

## The filter that looked free

`rtk` sits between the agent and the shell and shrinks command output before the model reads it. For `git log` the rewrite was simple. It dropped merge commits, since they are noise in most histories, and kept the one-line subjects. On a repo where every ticket lands as a feature commit, the output got much shorter and I saw no downside.

## Where it broke

Our release lane is gitflow. Hotfixes are cut from `master`, and the runbook computes the next hotfix version from two sources at once. One is the merge trail on the branch. The other is `git ls-remote --tags origin`. It takes the higher of the two and never trusts a single source. That rule exists because a single-source grep once tagged the same version twice.

The merge trail is merge commits. Once the filter stripped them, the log no longer answered the question the verification step was asking: is the hotfix merge the tip of the branch, and is the tag the agent expects the one that exists? What came back was a clean list of feature commits. The fix commit I was looking for was in it, so the check passed. Nothing in the output said that the merge above it, the one that makes it live, was missing or was somewhere other than where I assumed.

This happened twice. Both times I read the compressed log, saw the commit I expected, and treated the release as verified. Both times the raw history had to be re-read to find what the filtered version had hidden.

## The fix that rebuilt the hole

My first repair made things worse. I decided the filter was too blunt and narrowed it. I kept merge commits only when the subject matched a ticket id pattern, on the theory that the merges that mattered were the ones named after tickets. That is a heuristic on top of a heuristic. The merge that mattered for release verification is the one whose subject is `Merge branch 'master' into ...` or a tag merge, and those match no ticket pattern. I had rebuilt the same hole with a more elaborate rule. It cost a second false pass, and the second one was the more expensive because I now trusted the filter more, having tuned it.

The failure was not a bad regex. Any transformation between the repo and the reader has a rule for what counts as noise, and the reader can no longer see what the rule removed. For a status log that is fine. For a check that feeds a go/no-go decision, the removed part is the evidence.

## Raw for decisions, compressed for skimming

The rewritten global rules for `rtk` are short:

- Compression is allowed for output that a human or agent skims. That covers build logs, test output and directory listings.
- Compression is banned for any command whose output feeds a release or merge decision. That covers `git log` and `git tag` used for version math, `git ls-remote`, `git status` before a push, and branch-tip checks.
- Those commands run raw, every time, even when the output is long. The token cost is the price of the check.

Release verification also reads the tip directly instead of inferring it from a log. The check is `git rev-parse origin/master` compared against the tag's commit, plus the higher-of-both version rule the runbook already had. A one-line answer to a precise question is small enough that nothing needs compressing.

## Before you add a filter

Ask what the reader does with the result. If the answer is "decides whether to ship", leave that command out of the filter. The tokens saved on those calls were a few hundred a day. The false pass cost two re-verifications and a day of not trusting my own release log. Compressing output that never feeds a decision is a good trade. Compressing output that does feed one is where the trade goes wrong.
