Negative-class measurement: rejected, interrupted, denied, discarded, and reworked agent work
Measured 2026-09-03. Read-only. Scripts and intermediates in /tmp/panout-ideas/negclass/ (scan_claude.py, scan_codex.py, scan_git2.sh, analyze.py, claude_sessions.json, codex_sessions.json, git.tsv). No repo or log was modified.
Headline structural finding: there is no 180-day history on this machine
Every on-machine source bottoms out in mid-August 2026:
| Source | Oldest record | Newest record | Span |
|---|---|---|---|
| Claude Code JSONL (4 roots, 262 session files) | 2026-08-13 | 2026-09-03 | 21 days |
| Codex rollouts (95 JSONL) | 2026-08-21 | 2026-08-31 | 11 days |
| Git reflogs (21 repos) | earliest entry 2026-08-13 in every repo that has one | 2026-09-03 | 21 days |
The 30-day and 180-day windows are therefore identical for logs and reflog, and both are really "21 days". Only git log reaches back 180 days, because commit history predates the clone. Every "180d" column below that is not a git log column is the same number as its 30d counterpart. This is the single most important caveat in the report and it invalidates any trend claim (Table 3).
Table 1 — Negative events by type
| # | Event type | Source | Detection rule | 30d | 180d |
|---|---|---|---|---|---|
| 1 | Explicit tool-call rejection | Claude JSONL | tool_result content begins The user doesn't want to proceed with this tool use | 22 | 22 |
| 2 | User interrupt | Claude JSONL | text block begins [Request interrupted by user (13 bare, 12 "for tool use") | 25 | 25 |
| 3 | Permission denial (distinct field) | Claude JSONL | none — no field records a denial separately from #1 | 0 | 0 |
| 4 | Tool error (weak class) | Claude JSONL | tool_result.is_error === true | 280 | 280 |
| 5 | API error / model refusal (weak) | Claude JSONL | type:system, subtype:api_error (3) + model_refusal_fallback (2) | 5 | 5 |
| 6 | Codex turn abort | ~/.codex | payload.type == turn_aborted; all 14 have reason: "interrupted" | 14 | 14 |
| 7 | Codex patch-apply failure | ~/.codex | patch_apply_end.success != true | 0 (886 applies, 0 failures) | 0 |
| 8 | Stashed work | git, 21 repos | git stash list | 0 | 0 |
| 9 | Reset in reflog | git, 21 repos | reset: moving to | 23 | 23 |
| 10 | Rebase-related reflog entries | git, 21 repos | rebase in reflog message | 54 | 54 |
| 11 | Dropped stash in reflog | git, 21 repos | stash drop | 0 | 0 |
| 12 | Revert commits (all authors) | git log --all | subject ^Revert | 70 | 227 |
| 13 | Revert commits (founder-authored) | git log --all | subject ^Revert, author gareth@ | 1 | 22 |
| Hard negatives, Claude (1+2) | 47 | 47 | |||
| Hard negatives, all agent tooling (1+2+6) | 61 | 61 |
Denominators: Claude 15,642 tool_use events across 262 sessions; Codex 5,773 tool calls across 95 sessions. Combined agent action volume ≈ 21,415 tool calls; 61 hard negatives = 0.28 per 100 tool calls.
Rows 9/10 are unreliable as "discarded work" signals: reset: moving to does not distinguish --hard from --soft/--mixed, and git checkout -- <path> (the most common discard) leaves no reflog trace at all. Rows 12/13 are the only git-side signals with real 180-day reach.
Table 2 — Negative events per Claude session
262 sessions. Negative = rejection + interrupt.
| Negatives in session | Sessions | Share |
|---|---|---|
| 0 | 240 | 91.6% |
| 1 | 9 | 3.4% |
| 2–5 | 12 | 4.6% |
| >5 | 1 | 0.4% |
Including tool errors as negatives, the distribution shifts hard: 0 → 143 (54.6%), 1 → 55, 2–5 → 53, >5 → 11.
| Metric | Value | 95% CI (Wilson) |
|---|---|---|
Mean tool_use per session | 59.7 (median 41, max 628) | — |
| Sessions with 0 tool calls | 39 of 262 | — |
| Rejection rate = rejections / tool_use | 22 / 15,642 = 0.141% | 0.093–0.213% |
| Hard-negative rate (rej+int) / tool_use | 47 / 15,642 = 0.300% | 0.226–0.399% |
| Tool-error rate | 280 / 15,642 = 1.79% | 1.59–2.01% |
| Sessions with ≥1 hard negative | 22 / 262 = 8.4% | 5.6–12.4% |
| Codex abort rate | 14 / 5,773 = 0.24% | — |
| Codex sessions with ≥1 abort | 13 / 95 = 13.7% | — |
Sidechain (subagent) calls are 8,868 of 15,642 tool_use events (56.7%). Human rejection is structurally unavailable for most of that volume, which depresses the pooled rate.
Table 3 — Rate over time and by model (NOT interpretable as a trend)
By month:
| Month | Sessions | tool_use | Rej | Int | Errors | (Rej+Int)/100 tool_use |
|---|---|---|---|---|---|---|
| 2026-08 | 144 | 10,067 | 22 | 25 | 207 | 0.47 |
| 2026-09 (3 days) | 118 | 5,575 | 0 | 0 | 73 | 0.00 |
By ISO week — this is where the story breaks:
| Week of | Sessions | tool_use | Rej | Int | (Rej+Int)/100 tool_use |
|---|---|---|---|---|---|
| 2026-08-10 | 26 | 1,555 | 0 | 0 | 0.00 |
| 2026-08-17 | 90 | 5,899 | 22 | 22 | 0.75 |
| 2026-08-24 | 28 | 2,613 | 0 | 3 | 0.11 |
| 2026-08-31 | 118 | 5,575 | 0 | 0 | 0.00 |
All 47 negatives fall between 2026-08-17 and 2026-08-29. 23 of 47 (49%) landed on a single day, 2026-08-17. Day counts: 08-17 ×23, 08-18 ×9, 08-19 ×5, 08-23 ×5, 08-22 ×2, 08-24 ×1, 08-25 ×1, 08-29 ×1. The apparent "decline to zero" is one bad day plus a five-day zero tail.
By dominant model per session:
| Model | Sessions | tool_use | Rej | Int | Err | (Rej+Int)/100 tool_use |
|---|---|---|---|---|---|---|
| claude-opus-5 | 71 | 6,734 | 15 | 16 | 112 | 0.46 (CI 0.33–0.65) |
| claude-fable-5-1 | 93 | 4,436 | 0 | 0 | 64 | 0.00 (95% upper bound 0.068) |
| claude-fable-5 | 55 | 3,717 | 5 | 7 | 86 | 0.32 |
| claude-opus-4-8 | 19 | 627 | 0 | 0 | 9 | 0.00 |
| claude-sonnet-5 | 5 | 128 | 2 | 1 | 9 | 2.34 |
<synthetic> / none | 19 | 0 | 0 | 1 | 0 | — |
| gpt-5.6-sol (Codex) | 79 | 5,078 | — | 14 aborts | — | 0.28 |
| gpt-5.6-terra (Codex) | 5 | 430 | — | 0 | — | 0.00 |
| gpt-5.6-luna (Codex) | 9 | 265 | — | 0 | — | 0.00 |
History is too short to test whether the negative class is shrinking. 21 days, four weekly buckets, one of which carries half the events. The opus-5 vs fable-5-1 gap (0.46 vs 0.00, whose confidence intervals do not overlap) is arithmetically real but fully confounded with calendar time — fable-5-1 usage is concentrated in the zero-negative tail, so "newer model" and "later week" cannot be separated. No causal reading is supported.
Table 4 — Negatives by project directory and by rejected-file class
Project directories with any hard negative (all 30d = all history):
| Project dir (cwd) | Sessions | tool_use | Rej | Int | Err | (Rej+Int)/100 tool_use |
|---|---|---|---|---|---|---|
| /code/t3code/state/worktrees/poe2/t3code-ae2dc4bb | 2 | 206 | 4 | 4 | 8 | 3.88 |
| /code/t3code/state/worktrees/poe2/t3code-2dc05e5f | 17 | 823 | 12 | 8 | 20 | 2.43 |
| /code/personal/resume | 4 | 65 | 0 | 1 | 4 | 1.54 |
| /code/research/linear | 2 | 92 | 0 | 1 | 2 | 1.09 |
| /code/games/crossword | 7 | 248 | 1 | 1 | 20 | 0.81 |
| /code/research/panout | 33 | 718 | 1 | 4 | 11 | 0.70 |
| /code/dotfiles | 26 | 2,030 | 4 | 1 | 22 | 0.25 |
| /code/games/car-racer | 34 | 2,230 | 0 | 2 | 39 | 0.09 |
| /code/quora/work/poe2 | 64 | 5,047 | 0 | 3 | 69 | 0.06 |
| /code/jones | 28 | 1,542 | 0 | 0 | 23 | 0.00 |
| 22 other dirs (incl. all agent worktrees) | 45 | 2,641 | 0 | 0 | 62 | 0.00 |
The two t3code poe2 worktrees are 28 of 47 negatives (60%) on 1,029 tool calls (6.6% of volume). Whatever task class ran there is the negative-class hotspot by an order of magnitude.
By identity root: api 32 negatives / 3,530 tool_use (0.91 per 100); api-nozdr 15 / 11,504 (0.13); personal 0 / 608; ~/.claude/projects 0 / 0 (8 files, all with zero tool calls — this is why the prior 8-file measurement found nothing).
Rejected tool calls by tool and file class (n = 22; input path recoverable for 4):
| Tool | File class | Count |
|---|---|---|
| Bash | n/a (command, no path arg) | 11 |
| WebSearch | n/a | 6 |
| Edit | docs (.md) | 4 |
| WebFetch | n/a | 1 |
Every rejection with a recoverable path was a Markdown edit. Zero rejections touched code, test, or config files. Rejections cluster on side-effecting or externally-visible actions (shell commands, web calls) and on documentation writes — not on source edits.
Table 5 — Git-side negatives per repo
21 repos under /code (maxdepth 3, node_modules/.explore/vendor excluded).
| Repo | Stash | Reflog total | Reflog reset | Reflog rebase | Reverts 180d (all / gareth) | Reverts 30d (all / gareth) | Oldest reflog |
|---|---|---|---|---|---|---|---|
| /code/work/poe2 | 0 | 1,398 | 2 | 4 | 109 / 5 | 37 / 0 | 2026-08-13 |
| /code/work/poe-app-platform | 0 | 1,359 | 0 | 4 | 102 / 5 | 30 / 0 | 2026-08-13 |
| /code/jones | 0 | 287 | 7 | 9 | 3 / 3 | 1 / 1 | 2026-08-13 |
| /code/dotfiles | 0 | 160 | 8 | 13 | 0 / 0 | 0 / 0 | 2026-08-18 |
| /code/games/crossword | 0 | 135 | 1 | 0 | 0 / 0 | 0 / 0 | 2026-08-13 |
| /code/games/car-racer | 0 | 104 | 2 | 0 | 0 / 0 | 0 / 0 | 2026-08-13 |
| /code/app-platform-feedback | 0 | 61 | 0 | 20 | 0 / 0 | 0 / 0 | 2026-08-18 |
| /code/games/daily-drop | 0 | 39 | 0 | 0 | 0 / 0 | 0 / 0 | 2026-08-22 |
| /code/personal/dynorouter | 0 | 30 | 3 | 0 | 0 / 0 | 0 / 0 | 2026-08-19 |
| /code/work/work-brain | 0 | 11 | 0 | 4 | 0 / 0 | 0 / 0 | 2026-08-13 |
| /code/games/alpine-rush | 0 | 9 | 0 | 0 | 0 / 0 | 0 / 0 | 2026-08-13 |
| /code/games/typeracer | 0 | 9 | 0 | 0 | 0 / 0 | 0 / 0 | 2026-08-22 |
| /code/research/panout | 0 | 7 | 0 | 0 | 0 / 0 | 0 / 0 | 2026-08-22 |
| /code/personal/dynorouter-gateway | 0 | 6 | 0 | 0 | 2 / 2 | 0 / 0 | 2026-08-19 |
| /code/personal/resume | 0 | 6 | 0 | 0 | 0 / 0 | 0 / 0 | 2026-08-23 |
| /code/golfbench | 0 | 4 | 0 | 0 | 0 / 0 | 0 / 0 | 2026-08-27 |
| /code/personal/cursor-plugins | 0 | 3 | 0 | 0 | 3 / 0 | 2 / 0 | 2026-08-19 |
| /code/poe-browser | 0 | 3 | 0 | 0 | 7 / 7 | 0 / 0 | 2026-08-19 |
| /code/research/linear | 0 | 3 | 0 | 0 | 1 / 0 | 0 / 0 | 2026-08-22 |
| /code/jones-backup-20260813-2240 | 0 | 0 | 0 | 0 | 0 / 0 | 0 / 0 | — |
| /code/t3code/source | 0 | 0 | 0 | 0 | 0 / 0 | 0 / 0 | — |
| Total | 0 | 3,634 | 23 | 54 | 227 / 22 | 70 / 1 |
Zero stashes machine-wide. The 227 reverts are dominated by two shared Quora work repos whose revert traffic is overwhelmingly other engineers (top revert authors: jyoung-q 31/30, aaronalkan 25/24, kevlu94 10/10); founder-authored reverts total 22 in 180 days across all repos.
Rework within 30 days, from /tmp/panout-ideas/backtest/raw.json
raw.json is keyed by repo; each entry has results[] of {sha, ts, agent: bool, rw: bool, hrs} where rw = the commit's lines were touched again within 30 days (see backtest/measure.py:84 reworked(), window ts + 30d). Only commits at least 30 days old were sampled, capped at 400 per repo.
| Repo | Measured | Agent n | Agent reworked | Agent rw% | Human n | Human reworked | Human rw% |
|---|---|---|---|---|---|---|---|
| /code/work/poe-app-platform | 396 | 323 | 222 | 68.7% | 73 | 63 | 86.3% |
| /code/work/poe2 | 396 | 323 | 215 | 66.6% | 73 | 62 | 84.9% |
| /code/personal/dynorouter | 182 | 110 | 71 | 64.5% | 72 | 41 | 56.9% |
| /code/dotfiles | 399 | 85 | 54 | 63.5% | 314 | 89 | 28.3% |
| /code/personal/dynorouter-gateway | 68 | 44 | 24 | 54.5% | 24 | 11 | 45.8% |
| /code/jones | 397 | 50 | 27 | 54.0% | 347 | 155 | 44.7% |
| /code/poe-browser | 400 | 51 | 25 | 49.0% | 349 | 87 | 24.9% |
| /code/games/car-racer | 30 | 10 | 8 | 80.0% | 20 | 20 | 100.0% |
| /code/research/linear | 89 | 4 | 1 | 25.0% | 85 | 61 | 71.8% |
| /code/personal/cursor-plugins | 102 | 1 | 0 | 0.0% | 101 | 71 | 70.3% |
| /code/work/work-brain | 400 | 1 | 0 | 0.0% | 399 | 294 | 73.7% |
| /code/app-platform-feedback, /code/games/crossword | 0 | 0 | 0 | — | 0 | 0 | — |
| Total | 2,859 | 1,002 | 647 | 64.6% | 1,857 | 954 | 51.4% |
Rework is 2–3 orders of magnitude more common than in-session rejection (64.6% of agent commits vs 0.14% of tool calls). If "reworked within 30 days" counts as a negative, the negative class is enormous; if only explicit human refusal counts, it is nearly empty. These two definitions do not agree and the gap is the actual finding.
Statistical adequacy of the negative class
To distinguish a 5% from a 15% rejection rate at 95% confidence with 80% power (two-proportion test) requires 141 observations per class; 5% vs 10% requires 435 per class; estimating a single 5% rate to ±2 percentage points requires 457 observations. But the observed rate per tool call is 0.14% (rejections) / 0.30% (all hard negatives), not 5% — at that magnitude, separating 0.5% from 1.5% needs 1,553 observations per class, and separating 0.14% from 0.28% needs tens of thousands. Against the actual data: no single project directory, model, or week has enough negatives to support an autonomy-level claim. The largest cell is /code/t3code/state/worktrees/poe2/t3code-2dc05e5f with 20 negatives on 823 tool calls, and the largest model cell is claude-opus-5 with 31 on 6,734. Only the session-level framing gets close: 22 of 262 sessions contain a hard negative (8.4%, CI 5.6–12.4%), and 262 sessions is above the 141-per-class bar for a coarse 5%-vs-15% split — but only as one pooled number, since splitting it by project or model immediately drops every cell below n=100. No project, task class, or model on this machine currently has enough negative-class data to certify an autonomy level, and at the observed base rate the required sample is roughly 100× the data on disk.
Caveats
- 21 days of history, not 180. Logs and reflogs begin 2026-08-13 in every root. 30d and 180d are the same window for everything except
git log. The machine appears to have been provisioned or reset around that date. - The trend in Table 3 is one day. 23 of 47 negatives are 2026-08-17. Four weekly buckets cannot establish direction.
- Model comparison is confounded with time. fable-5-1's 0/4,436 is real but sits entirely in the zero-negative tail of the window; opus-5 usage sits in the burst.
- 56.7% of tool calls are subagent (sidechain) calls that a human cannot interrupt or reject, so the pooled rejection rate understates the per-human-visible-action rate by roughly 2×. A subagent-excluded denominator would give 47/6,774 = 0.69 per 100.
- Substring matching is unsafe here. Naive greps for "Denied"/"rejected"/"aborted" return 229/5/138 hits, nearly all false positives from file contents and from prior measurement runs that echoed the marker strings into tool output. All counts above use anchored prefix matching on
tool_resultand text blocks. This report's own session is in the corpus and contributes 0 negatives. - No permission-denial field exists. Denials are indistinguishable from rejections in the log format; row 3 of Table 1 is structurally zero, not empirically zero.
- Rejected-path recovery is 4/22. Bash and WebSearch rejections carry no file path, so the file-class breakdown in Table 4 rests on four events.
git checkout -- <path>and uncommitted discards are invisible. The reflog records no such event; reflogresetentries do not distinguish--hardfrom--soft.- Revert counts in the two Quora repos are org-wide, not this machine's. 211 of 227 reverts come from repos where the founder authored 10.
- Rework ≠ defect.
rwin raw.json means the same lines were touched again within 30 days, which also captures normal iteration on active files; human rework is 51.4%, so the metric has a very high floor. Rework figures are sampled (cap 400/repo) and cover commits ≥30 days old, a different and older population than the 21-day log window. - Codex has no approval-decision record. All 14
turn_abortedevents carryreason: "interrupted"; no denial/approval event type exists in the rollout schema. ~/.claude/projectsholds 8 session files with zero tool calls. Any measurement scoped to that root alone measures nothing.