Skip to content

feat(filter): reduce observed agent confusion in git diff/status/log#320

Merged
mpecan merged 1 commit intomainfrom
feat/git-filter-confusion-fixes
Apr 8, 2026
Merged

feat(filter): reduce observed agent confusion in git diff/status/log#320
mpecan merged 1 commit intomainfrom
feat/git-filter-confusion-fixes

Conversation

@mpecan
Copy link
Copy Markdown
Owner

@mpecan mpecan commented Apr 8, 2026

Summary

Three related fixes informed by analysing ~54k tokf events from local tracking.db. Each addresses a distinct retry-burst pattern where an agent thrashes through flag variations trying to "escape" a filter.

  • git/diff — added passthrough_args so the model can get -p/--patch/--no-stat/-U<n>/--name-only/--name-status/--numstat/--shortstat/--raw content out of the forced --stat override. The previous behaviour caused 51-call retry bursts (model trying every workaround it knew, including git --no-pager diff).
  • git/statusrun override now uses --porcelain=v1 -b -uall --find-renames so untracked files in newly-created directories appear individually (instead of ?? new_dir/) and renames render as R old -> new (instead of D old + ?? new looking unrelated). Branch-line replace rules now always communicate upstream sync state: [synced], [ahead N], [behind N], (no upstream) — previously the upstream was stripped when in sync, so the model couldn't tell whether commits had been pushed.
  • git/log — empty output now emits an on_empty hint pointing at the most likely causes (untracked pathspec, missing --all, missing --follow) instead of nothing. Previously the model would burn 10–40 calls cycling through --all, --diff-filter=A, --follow, --grep, --source, '-- pathspec' variants trying to escape a non-existent filter — when the actual answer was "the file is untracked, run git ls-files". Also added passthrough for output-format flags incompatible with --oneline -n 20: --name-only, --name-status, --shortstat, --dirstat, -L.

Evidence (from tracking.db, 2026-02-18 → 2026-04-08)

Filter Biggest burst Burst pattern
git/diff 51 calls in 3m41s model tries every output-format variant (-p, --no-stat, git --no-pager diff, --no-index /dev/null <file>)
git/status observed cycling on missing files in new dirs (per maintainer feedback) ?? new_dir/ collapses path of just-created file
git/log 44 calls / 22 calls in single bursts model passes --all, --diff-filter=A, --source, --follow, pathspecs; gets empty back; can't tell why

Across the dataset, git/diff calls contained 86 explicit --no-stat, 127 -p/--patch, and 27 --no-pager workaround flags — clear "I am trying to escape your filter" signals from agents.

Test plan

  • cargo run -p tokf -- verify git/diff --scope stdlib → 4/4 passed
  • cargo run -p tokf -- verify git/status --scope stdlib → 9/9 passed (incl. 2 new regression tests for -uall and --find-renames)
  • cargo run -p tokf -- verify git/log --scope stdlib → 2/2 passed (empty test now asserts the on_empty hint)
  • cargo run -p tokf -- verify --scope stdlib134/134 passed
  • cargo test --workspace1965 passed, 0 failed, 166 ignored
  • cargo clippy --workspace --all-targets -- -D warnings → clean
  • cargo fmt --check → clean
  • bash scripts/generate-readme.sh → README up to date with new docs rows

Files

Filters

  • crates/tokf-cli/filters/git/diff.toml — added passthrough_args
  • crates/tokf-cli/filters/git/status.toml — new run override + new replace rules
  • crates/tokf-cli/filters/git/log.toml — added passthrough_args + on_empty hint

Tests

  • crates/tokf-cli/filters/git/status_test/untracked_in_new_dir.toml (new)
  • crates/tokf-cli/filters/git/status_test/rename_detected.toml (new)
  • crates/tokf-cli/filters/git/status_test/{clean,normal,local_only_branch}.toml (updated for new branch markers)
  • crates/tokf-cli/filters/git/log_test/empty.toml (asserts on_empty hint)
  • crates/tokf-cli/src/config/types.rstest_deserialize_git_{diff,status,log} updated to assert new fields, passthrough entries, and prefix-matching behaviour for -U3, --patch-with-stat, -L1,10:src/main.rs

Docs

  • docs/getting-started.md — stdlib filter table entries for git/diff, git/status, git/log
  • README.md — regenerated

Follow-up (separate work)

🤖 Generated with Claude Code

Three related fixes informed by analysing ~54k tokf events from local
tracking.db. Each addresses a distinct retry-burst pattern where the
model thrashes through flag variations trying to "escape" the filter.

git/diff
- Forced --stat had no escape hatch, so models repeatedly tried
  --no-stat, -p, --no-pager, etc. (240+ workaround flags across the
  dataset; biggest single burst: 51 calls in 3m41s).
- Added passthrough_args for the output-format flags the model already
  reaches for: -p/--patch, --no-stat, -U<n>, --name-only/--name-status,
  --numstat, --shortstat, --raw.

git/status
- Porcelain default (-unormal) collapsed untracked directories to
  "?? newdir/", so models couldn't see files they had just created and
  would loop. Run override now uses
  `git status --porcelain=v1 -b -uall --find-renames` so every untracked
  file appears individually and renames render as "R old -> new" instead
  of D + ?? on separate lines.
- Branch-line replace rules now always communicate upstream sync state
  ([synced], [ahead N], [behind N], (no upstream)). Previously the
  upstream was stripped when in sync, leaving the model unable to tell
  whether commits had been pushed.

git/log
- Empty output was indistinguishable from filter-induced suppression —
  models would burn 10–40 calls cycling through --all, --diff-filter=A,
  --follow, --grep, --source, '-- pathspec' variants trying to escape a
  non-existent filter. Added an `on_empty` hint that points at the most
  likely causes (untracked pathspec, missing --all, missing --follow).
- Added passthrough for output-format flags incompatible with
  --oneline -n 20: --name-only, --name-status, --shortstat, --dirstat,
  -L (line-history). Other flags (--all, --follow, --diff-filter,
  --grep, -S, -G, --author, --since) compose fine with the override.

Tests
- New regression cases:
    git/status_test/untracked_in_new_dir.toml (-uall)
    git/status_test/rename_detected.toml (--find-renames)
- Updated existing fixtures for the new branch-line markers:
    git/status_test/{clean,normal,local_only_branch}.toml
- Updated git/log_test/empty.toml to assert the on_empty hint.
- test_deserialize_git_{diff,status,log} unit tests in
  crates/tokf-cli/src/config/types.rs assert the new fields,
  passthrough_args entries, and prefix-matching behaviour for flags
  like -U3, --patch-with-stat, -L1,10:src/main.rs.

Verified
- cargo run -p tokf -- verify --scope stdlib  -> 134/134 passed
- cargo test --workspace                     -> 1965 passed, 0 failed
- cargo clippy --workspace --all-targets -- -D warnings -> clean
- cargo fmt --check                          -> clean

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@repository-butler
Copy link
Copy Markdown
Contributor

Filter Verification Report

Changed Filters

Filter Status Tests Passed Failed
git/diff 4 4 0
git/log 2 2 0
git/status 9 9 0

All Filters Summary

✅ 134/134 test cases passed across 49 filters


Generated by tokf verify

@mpecan mpecan merged commit 6992712 into main Apr 8, 2026
5 checks passed
@mpecan mpecan deleted the feat/git-filter-confusion-fixes branch April 8, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant