rtk-ai / rtk-ai/rtk

Independent audit of v0.48.0 truncation: 4 historical failure classes fixed, JSON enum truncation remains (repro + data)

Open
#4,073 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:security bug needs-info priority:high
Dominant language
Rust
Stars
81.1k
Forks
5.1k
Avg merge
4d 11h
Merged PRs (30d)
40

Description

Independent audit: RTK v0.48.0 output truncation — what is fixed, what remains

Audited with context-loss-audit (npm) · 2026-09-15 · Windows 11 x64 · rtk 0.48.0 (dev-0.50.0-rc.439 build)

TL;DR

I audited five truncation-prone scenarios against rtk 0.48.0, comparing raw command output with rtk output line by line. Two findings:

  1. Most of the historical failures are fixed. Four of the failure classes reported in #1313 (March 2026) did not reproduce on 0.48.0: git status shows all modified/untracked files, grep shows all 60 matches, git log keeps BREAKING CHANGE: in the commit body, and git diff is not cut at 10 changes per file. This matches the truncation fixes in the v0.34.0 release notes. Credit where due — and it also means older third-party comparisons may be stale.
  2. JSON enum truncation still reproduces, and it is the most dangerous class. An 8-value array becomes ["admin", ... +7 more]. Nothing errors; an agent that generates validation logic from the visible values will lock out legitimate ones. Repro below.

Method

Five scenarios built in a throwaway git repo (Windows 11, rtk 0.48.0, the rtk-x86_64-pc-windows-msvc build from release dev-0.50.0-rc.439):

# Command What it stresses
1 rtk git status 25 modified + 8 untracked files
2 rtk grep -rn deprecated_api --include=*.js . 60 matches in 3 files (the 25-per-file cap)
3 rtk git log -15 15 commits; BREAKING CHANGE: on the 3rd body line
4 rtk json roles.json 8 enum values in one array
5 rtk git diff 3 files × 25 changed lines, one FIXME: security token line

Each pair (raw output, rtk output) was audited with ctxaudit audit --raw … --compressed … --json, which classifies every deleted line as noise (provably redundant) or signal, and checks disclosure quality of truncation markers.

Results

# Scenario raw → rtk bytes Saved Verdict Truncation marker
1 git status 1038 → 482 53.6% lossy (cosmetic) none — all 33 files shown
2 grep (60 matches) 3426 → 3426 0% clean none — all 60 shown
3 git log -15 2996 → 1574 47.5% lossy (cosmetic) none — BREAKING CHANGE kept
4 json (8 enum values) 181 → 72 60.2% dangerous ... +7 more (explicit count)
5 git diff 2734 → 2710 0.9% lossy (cosmetic) none — FIXME line kept

"lossy (cosmetic)" means the audit classified deleted lines as signal only because they were format headers (Author:, Date:, diff --git, index …) that rtk re-renders in compact form — no information is actually lost. The audit tool is deliberately conservative here and I report it as such.

The one that still bites: enum truncation

Input (roles.json):

{ "status": "ok", "allowed_roles": ["admin", "editor", "reviewer", "publisher", "auditor", "moderator", "archivist", "guest"], "count": 8 }

rtk output:

{
  allowed_roles:
  ["admin", ... +7 more]
  count: 8
  status: "ok"
}

Audit verdict: dangerous, severity critical. The marker ... +7 more is explicit-counted (good disclosure — better than silent), but for enum-like arrays an explicit marker does not help an agent: validation logic generated from ["admin"] rejects the other 7 legitimate roles, and the agent never learns them from the compressed view. count: 8 happens to leak the true size here, but nothing tells the agent the array was cut in a way that matters.

Suggestion: treat small string arrays (say ≤32 elements, all short scalars) as never-truncate — the byte savings on an 8-element enum were 109 bytes; the failure mode is disproportionate to the saving. This is the one case where I'd argue the compact form is strictly worse than the raw form.

Historical cross-check (issue #1313)

Failure class in #1313 (2026-03) v0.48.0 (2026-09)
git status truncated (15 modified / 10 untracked) not reproduced — 25+8 all shown
grep 25-per-file cap not reproduced — 60 matches shown
git log body cut at 3 lines, BREAKING CHANGE dropped not reproduced — 3rd-line BREAKING CHANGE kept
diff cut at 10 changes/file not reproduced — 25 lines/file shown
JSON enum cut at 5 entries still reproduces (8 → 1 shown, ... +7 more)

Consistent with the v0.34.0 release notes (diff: never truncate diff content, read: default to no filtering, git: replace vague truncation markers with exact counts). Two things still stand from that thread: there is no global lossless switch (the no_truncation/--lossless work by RKelln appears not to be merged), and the enum/JSON path behaves differently from the fixed paths above — which makes the remaining behavior harder to predict than the fixed ones.

Limitations

  • Five scenarios, one platform (Windows), one build (0.48.0). Config files (.rtk/…) were absent/defaults.
  • The audit tool classifies conservative; "lossy (cosmetic)" rows would be "clean" under a smarter header-awareness rule. I kept the conservative output.
  • I did not measure token savings claims (see #2001 for that discussion).

Tool

context-loss-audit — audits what an output compressor threw away by comparing raw and compressed output line by line: noise vs signal, disclosure quality of markers (explicit / vague / silent), exit code contract (0 ok / 1 dangerous). MIT, zero deps: npx -y context-loss-audit --help.

Not a competitor to rtk — it does not compress anything; it is the verification layer for compressors.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the reported case with rtk json roles.json using the eight-value allowed_roles array, then trace the JSON formatting and truncation path it exercises. No source file or test is named, so locate the relevant Rust implementation and existing coverage first; done means small string arrays retain every value without the ... +N more output.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.