The turn verdict
Which of these did I just do?
A finding you introduced thirty seconds ago and a finding you inherited from a repository's first year are not the same object. owlwarden turn tells them apart. Carried findings never fail a turn, at any threshold.
Three states, one gate
- NEW IntroducedPresent now, absent at the base. Can fail the turn.
- OLD CarriedAlready at HEAD. Counted on one line, never fails.
- FIX FixedGone since the base. Reported, never fails.
npx owlwarden turn
◉ᴥ◉ turn / 7 files / since HEAD a1b2c3d / 0.31s
✔ clean - nothing introduced
2 fixed / 5 carried (already at a1b2c3d, not this turn's)
Three states. One of them can fail the turn.
| State | Meaning | Can fail the turn |
|---|---|---|
introduced | present now, absent at the base | yes |
carried | present in both | no |
fixed | present at the base, absent now | no |
Carried findings never fail a turn, at any threshold. There is no flag that changes it and no code path that could grow one: the gate is applied to the introduced set before it is consulted. A control that blocks on debt the turn did not create is a control that gets removed on the second day, and everything it would have caught goes with it.
When something is introduced
◉ᴥ◉ turn / 1 file / since HEAD a8a6b93 / 0.16s
✘ blocked - 1 introduced at or above high
1 carried (already at HEAD a8a6b93, not this turn's)
Everything introduced is reported whether or not it blocks. A turn
that adds a medium under a high gate reads
clean at high - 1 introduced below the bar, shown anyway.
The verdict never prints nothing introduced over something the
turn introduced.
In an agent's loop
npx owlwarden init --claude-code
That writes a Stop hook running
turn --hook claude-code --record. Per-edit and pre-command
hooks stay on gate: those must be cheap and have no
meaningful base to compare against.
Under --hook, stdout is the host's own JSON. The reason the
model receives names what is new and says the rest were already
there: an agent told "there are eighteen findings" starts fixing files
nobody asked it to touch, in a session the developer is paying for.
Claude Code / Cursor / MCP
In CI, on a pull request
The base is a flag, so the "turn" can be a whole branch:
- run: npx owlwarden turn --base origin/${{ github.base_ref }} --fail-on medium
This fails the job for what the branch introduced and stays silent about
what main already carried. Use owlwarden scan in a
scheduled job for the whole repository - that is a different question,
asked at a different time. Needs the full history: set
fetch-depth: 0 on actions/checkout.
The rest of the CI contract.
Keeping a record
npx owlwarden turn --record
One JSON line per turn in .owlwarden/turns.jsonl, bounded at
the last 200. Every field but the timestamp and the stopwatch is derived
from the two reports and the base, so two runs over an unchanged tree
produce identical records. Commit the file if you want the audit trail in
review; gitignore it if you do not.
What a clean turn does not mean
clean is a claim about a comparison. It means
nothing was introduced since that commit, never
this repository is clean. The base is printed on every line of
the output for exactly that reason, and owlwarden scan is the
command that answers the other question.
The base is a commit, so the verdict is as trustworthy as the commit is.
An agent that can commit can commit a finding and have the next turn
report it as carried. This is a detection and review control, not a
containment one - the same limit seal states about
itself. If that matters for your threat model, run
turn --base origin/main in CI, where the base is one somebody
else set.
Over 400 changed files, turn refuses. That is a merge or a
reformat, not a turn, and the verdict a developer wanted is not in there.
Your index and working tree are never touched: git status is
byte-identical across a run, staged changes included.
Keep reading
- owlwarden turnWhich of these did I just do?
- RulesTrigger, confidence, and framework-specific fix.
- Agent configHooks, MCP servers, instructions, and editor tasks.
- owlwarden vetCheck a repository before you open it.
- owlwarden sealNotice when your agent's execution surface moves.
- ExposureWhich of these findings do I fix first?
- RuntimesDoes this fix run on Bun, Deno, or Workers?
- CoverageMapped rules and categories static analysis cannot cover.