Ctrl K
ComunidadGuías…

docs/incidents.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Incidents

Defects that reached a user or a published release, kept as the eval set for every review layer ("incidents are the
eval", from the Claude Code team's code review write-up, 2026-10-26). A row is added in the same change that fixes
the defect: the fix commit, the commit that introduced it when known, the earliest layer that should have caught it,
and the test or gate that catches it now. `scripts/audit_incidents.py` (run by `scripts/check.sh` and the Security
Checks job) fails a row whose commit does not resolve, whose layer is not one of the names below, or whose catcher is
not defined in the code.

A catcher is written in backticks and is one of: the exact name of a Bats `@test` under `tests/`, a Go `Test*`
function in a `_test.go` file, a Python `test_*` function under `tests/` or `scripts/`, or the repository path of a
gate script (for example `scripts/audit_timeout_status.py`). A Bats name that holds a `|` cannot sit in this table;
rename the test.

Layers, earliest first:

- `write-time`: the author's own check before committing, a sweep of same-shape sites and the source gates, plus the
  `.githooks/pre-commit` hook.
- `check`: `./scripts/check.sh --no-format` (ShellCheck, golangci-lint, the `scripts/audit_*.py` gates), locally and
  in the Check workflow.
- `unit`: the Bats suite through `./scripts/test.sh` and `go test ./...`, locally and in the Validation workflow on
  macos-26.
- `compat`: the Validation workflow's macos-15 Bats subset, the only lane that sees another macOS
  version's tool output.
- `review`: a diff review, the line-by-line review AGENTS.md requires for destructive sinks, or the weekly audit.
- `e2e`: `scripts/e2e_macos.py` on a real Mac before a release.
- `release`: the release-flow pre-flight and `release.yml` (minimum-OS check, Nix, Homebrew).
- `field`: only a real user's machine, network or configuration shows it.

When a review skill, its prompt or the model running it changes, rerun it on the files each fix touched as they were
at `<Fixed>^` and record which rows it finds (`.claude/skills/weekly-audit`, Phase 3). `Introduced` is a commit only
when it was confirmed by reading the history, otherwise `unknown`.

## Incidents

| ID | Reported | Symptom | Introduced | Fixed | Layer | Caught by |
|---|---|---|---|---|---|---|
| I-01 | 2026-09-20 | Editor obsolete-extension cleanup found nothing on macOS 15, and a nested `.obsolete` key could be offered as an extension directory | 6e70669f | 04cb4947 | compat | `only a root-level .obsolete key marks an extension, never a nested one (#1512)`, `a .obsolete value must be boolean true, not 1 or the string true (#1512)` |
| I-02 | 2026-10-05 | `mo clean` removed project caches that Git tracks, leaving deleted tracked files in the user's clones | unknown | d929d156 | review | `clean_project_caches keeps project caches that Git tracks` |
| I-03 | 2026-10-05 | `mo clean` removed the `~/Library/Logs/DiagnosticReports` directory itself, so macOS could no longer save crash reports | unknown | 4ab50c73 | unit | `clean_user_essentials keeps the DiagnosticReports directory (#1689)` |
| I-04 | 2026-10-18 | `mo update` aborted with a connection error when the GitHub API was rate limited, although install.sh and nightly updates fell back to git tags | unknown | 2e88f475 | review | `stable discovery falls back to git release tags when HTTP API lookups fail` |
| I-05 | 2026-10-18 | Incomplete browser downloads were never found when the home folder name contained a space | cfa0a820 | d822ad0b | unit | `incomplete downloads scan discovers files when HOME contains spaces` |
| I-06 | 2026-10-22 | A shell PATH without `/usr/sbin` read total memory as 0 and refused `mo slim` on Apple Silicon | unknown | b03c0f54 | write-time | `sysctl never resolves through PATH (#1804)`, `get_memory_info reads total memory without /usr/sbin in PATH (#1804)` |
| I-07 | 2026-10-22 | `mo purge` refused every item under a `/System/Volumes/Data` path listed in purge_paths as a critical system path | unknown | 70d320e1 | unit | `validate_path_for_deletion judges a Data volume path by the root path that reaches it (#1814)` |
| I-08 | 2026-10-23 | `mo touchid` reported Touch ID as enabled when the only `pam_tid.so` line was commented out | unknown | 69d2a3c7 | unit | `check_touchid_support ignores a commented-out pam_tid line (#1815)`, `touchid enables the line sudo_local.template ships commented out (#1815)` |
| I-09 | 2026-10-27 | `mo optimize` reported Network Cache Refresh as failed on every run on macOS 27, which refuses `launchctl kill` on mDNSResponder even to root (#1867) | fb920811 | 29b9699d | field | `DNS refresh retries a macOS-refused service signal only as the mDNSResponder account` |
| I-10 | 2026-10-27 | Dry-run find scans sized and recorded each candidate twice and returned 1 when no preview ledger was set up (#1865) | 70eed1b0 | a703eddc | review | `safe_find_delete dry run records each target once without removal fallthrough (#1865)`, `safe_sudo_find_delete dry run records targets once and tracks count (#1865)` |
| I-11 | 2026-10-27 | `mo clean` removed installed npx packages while running commands still needed their resources and modules (#1870) | unknown | f954e2fd | unit | `clean_dev_npm preserves installed npx packages in default and custom caches (#1870)` |
| I-12 | 2026-10-30 | `mo purge --debug` kept every node_modules as "Could not inspect" and exited 1, because `run_with_timeout`'s debug notice landed in the captured lsof output; found by the V1.66.0 release e2e | unknown | e4686b6e | unit | `run_with_timeout keeps its debug notice out of captured command output`, `purge node project process check reads an idle project as idle under --debug` |
| I-13 | 2026-10-26 | Cleaning Kitty's graphics-protocol cache broke image transfers in a running terminal session (#1856) | unknown | e7b15113 | review | `a custom whitelist still protects system caches, Kitty, Poetry virtualenvs, the renv cache, pnpm dlx and llama.cpp models` |
| I-14 | 2026-10-26 | Users whose network needed the macOS system proxy did not receive background update notices because curl connected directly | unknown | 2748db02 | field | `background update lookup waits longer and follows the system proxy while foreground lookups do not` |
| I-15 | 2026-10-26 | Old flat Analyze cache files remained for users who no longer ran Analyze, and a large accumulated directory froze tools that listed it | unknown | a152d651 | review | `legacy analyzer cache sweep removes only flat analyzer files from ~/.cache/mole`, `legacy analyzer cache sweep skips dry runs and a symlinked cache root`, `clean starts the legacy analyzer cache sweep in the background` |
| I-16 | 2026-10-30 | Simulator cleanup could treat failed optional metadata reads as an absent key and suppress cancellation, allowing a device leaf to be removed after an incomplete probe | 437227e1 | f8950db2 | unit | `simulator device metadata timeouts retain the device and signals stop later devices` |
| I-17 | 2026-10-30 | Darwin temporary-root pruning could discard an unreadable live registry and remove an old temporary file still owned by that process | ff2640de | f8950db2 | unit | `Darwin temp prune retains every candidate when a live registry cannot be read` |
| I-18 | 2026-10-30 | Emptying a Trash of about 17,000 small folders ran 18 minutes behind a bare "Emptying trash..." spinner with no count, which the user reported as stuck | unknown | 5b62cc12 | field | `emptying a large Trash reports its count every 100 items` |
| I-19 | 2026-10-28 | `mo optimize` pruned Spotlight's own `Custom.relatedContents` rule as an orphan, so Show Related Content turned itself back on (#1878) | unknown | ea7abfc9 | unit | `opt_prune_spotlight_orphan_rules keeps Spotlight's own switches (#1878)` |
| I-20 | 2026-10-31 | `mo clean` cleaned Chrome's and Brave's `~/Library/Caches` roots while the browser ran, although the Application Support leaves beside them already waited for it | unknown | 3aa4ed7f | write-time | `clean_browsers holds Chrome and Brave Caches roots while the browser runs` |
| I-21 | 2026-10-31 | `mo clean` cleaned Adobe's shared `Media Cache Files` while Premiere Pro, After Effects or another Adobe video app had them in use | unknown | ecf2f800 | review | `clean_design_tools holds Adobe media cache files while an Adobe video app runs` |
| I-22 | 2026-11-01 | Automatic cleanup removed Yarn Berry global archives that Plug'n'Play projects load as installed dependencies | 21d44166 | e59e7d60 | review | `clean_dev_npm keeps Yarn Berry dependencies and cleans only Yarn Classic`, `Yarn Berry producer and sink preserve dependencies with the default whitelist`, `Yarn Berry producer and sink preserve dependencies with a custom whitelist` |
| I-23 | 2026-11-01 | `mo uninstall` printed `[[: invalid regular expression: empty (sub)expression` under Bash 4+ (#1896): the NUL-byte check on decoded uninstall lists matched `$'\0'`, an empty regex, and never rejected anything on any Bash | 61644caf | 671f2c43 | unit | `decode_file_list rejects NUL bytes without an empty regex error`, `decode_bundle_id_list rejects NUL bytes without an empty regex error`, `decode_file_list keeps non-UTF-8 paths under a UTF-8 locale` |
| I-24 | 2026-11-02 | `mo uninstall` of a channel build (Zed Nightly) offered the stable app's base-name folders while the stable app was installed, and the stable app took folders a channel build still used | unknown | fadc47a7 | review | `find_app_files leaves the stable app's base-name folders to it while it is installed`, `find_app_files leaves the family's name folders to a channel build still installed`, `find_app_system_files leaves the family's system folders to another installed build`, `find_app_files accepts an empty family-filtered result under Bash 3.2 nounset` |
| I-25 | 2026-11-02 | `mo uninstall` exited 0 after an app failed to uninstall, so scripts read a failed removal as success | unknown | 4b548846 | unit | `by-name uninstall exits 1 when an app fails and 0 when none did`, `interactive uninstall still exits 1 when an app failed before the user quits with q`, `batch_uninstall_applications adds a failed app removal to MOLE_UNINSTALL_FAILED_APPS` |
| I-26 | 2026-11-02 | `mo clean` emptied `~/Library/Caches/Adobe` and `com.adobe.*` while Photoshop, Bridge or Lightroom Classic ran | unknown | 1191dfe2 | review | `clean_design_tools holds shared Adobe caches while an Adobe app runs but not for Creative Cloud residents` |
| I-27 | 2026-11-02 | `mo analyze` could move `~/Library/Mobile Documents`, an app's iCloud container or its `Documents` folder to the Trash, removing that store from every device on the account | unknown | 17d94dd5 | review | `TestAnalyzeDeleteRefusesICloudStructuralFoldersButNotTheirContents`, `TestAnalyzeDeleteRefusesICloudStructuralFoldersReachedThroughAnotherPath`, `TestAnalyzeDeleteAllowsICloudFilesAtStructuralDepths`, `TestAnalyzeDeleteRefusesParentsOfExistingICloudState` |
| I-28 | 2026-11-02 | With Touch ID enabled for sudo on macOS 27, `mo clean` opened the authorization dialog twice: Mole killed the first `sudo -v` after five seconds and started another, discarding a password typed into the first dialog | unknown | 80d88ea6 | unit | `request_sudo_access waits for one Touch ID dialog instead of opening a second` |
| I-29 | 2026-11-02 | `mo update` copied `bin/` and `lib/` with an unchecked `cp -r`, so a root-owned file or directory left by an earlier sudo install kept stale modules while the update printed success, and a 1.67.0 launcher ran beside July `remove.sh` and `catalog.sh` | unknown | e50a170a | unit | `install_files replaces read-only files an earlier sudo install left in the config tree`, `install_files keeps the pinned launcher and names a safe next step when a config directory refuses the copy` |
| I-30 | 2026-11-04 | On a Mac where Spotlight indexed the folder, `mo uninstall` listed a lone hidden bundle such as `.Solo.app` as `.Solo`, because the mdls fallback returns the bundle's file name; CI, with Spotlight off, read the plist name, so the #1791 case failed only on the maintainer's Mac | 68696564 | 94a8af5c | unit | `uninstall_resolve_display_name never shows a hidden bundle's file name (#1791)` |
| I-31 | 2026-11-04 | The shell timeout fallback installed its INT trap after starting the command, so a Ctrl-C in that window exited the shell and left the command running until the killer's deadline; CI saw it as `ORPHANED:plain` | fef4f3c6 | 9883c619 | review | `run_with_timeout shell fallback traps INT before the command starts`, `run_with_timeout shell fallback never starts a command after an early interrupt` |
| I-32 | 2026-11-04 | `mo analyze` printed sizes that round up to the next unit as `1000.0 kB` (999,999 B) where Finder shows 1 MB, because `units.BytesSI` picked the unit before rounding (#1914) | unknown | 2335f055 | unit | `TestBytesSI` |
| I-33 | 2026-11-04 | `mo status` shortened process names by bytes while its callers pass a display width, so a Korean, accented or curly-apostrophe name was cut while it still fit and a cut could split a UTF-8 rune into `�` (#1917) | unknown | c70d4731 | unit | `TestShorten` |
| I-34 | 2026-11-04 | `mo analyze` measured names with a hand-written rune table, so NFD accents, halfwidth kana, CJK punctuation such as `、` and joined emoji padded the name column one to nine cells off and pushed the size column out of line; Mole CLI (Windows) had moved to grapheme widths in 787b333f and the sync did not carry it back | unknown | 8098ac2c | review | `TestUnicodeColumnsPreserveGraphemes` |
| I-35 | 2026-11-04 | Under `bin/uninstall.sh`'s `LC_ALL=C`, `mo uninstall --list` byte-sliced and byte-padded the UNINSTALL NAME column, so a CJK name split a character and moved SIZE out of line, and spinner messages counted bytes or characters instead of cells, so a CJK app name overflowed or split | unknown | 5324a06e | review | `uninstall --list text table keeps the size column aligned for CJK uninstall names`, `format_spinner_message fits a CJK name by display width in both locales` |
| I-36 | 2026-11-04 | `truncate_by_display_width` tested each character with the regex `[[:ascii:]]`, which macOS bash 3.2 never matches and glibc rejects, so every character counted two columns and long names in uninstall, purge, installer and slim lists were cut about twice too early (#1918) | unknown | 5eba36a2 | write-time | `truncate_by_display_width counts ASCII as one column (#1918)` |
| I-37 | 2026-10-28 | The generic user cache sweep removed `~/Library/Caches/Google` whole, so Chrome's live cache went while Chrome ran, bypassing the Chrome row that waits for it to quit, and the folder failed on seven clean runs | unknown | d2341ba9 | review | `clean_user_essentials leaves Caches/Google to the Chrome and Android Studio rows` |
| I-38 | 2026-11-05 | With a remote Docker context selected, `mo clean` reported the remote engine's storage as Docker storage and hid the local Docker Desktop data row, and each Docker probe waited out its timeout on an unreachable host (#1922) | cde39aae | 4075102a | field | `large files never queries a remote Docker engine (#1922)`, `clean_dev_docker never prunes a remote, unknown or stopped Docker engine (#1922)`, `idle VM never asks a remote Docker engine about containers (#1922)` |
| I-39 | 2026-11-06 | The generic Application Support sweep cleared Code Cache and GPUCache of running Electron apps such as Docker Desktop, VS Code and T3 Code, found on the test Mac while checking #1922 | unknown | 8abe329d | review | `clean_application_support_logs keeps caches of a running Electron app` |
| I-40 | 2026-11-01 | A purge_paths file without a final newline lost its last root; a single-root configuration fell back to discovery and could be overwritten | unknown | d338900c | unit | `purge paths preserves a single custom path without a final newline`, `load_purge_config includes the final custom path without a newline` |
| I-41 | 2026-11-07 | `mo purge --paths` treated an editor command such as `code --wait` as one executable name, so standard EDITOR or VISUAL settings could not open the configuration | unknown | 4917abd1 | unit | `purge paths accepts editor commands with arguments and keeps the config path literal`, `purge paths accepts quoted editor paths and arguments`, `purge paths returns editor failures without reporting a configuration update` |
| I-42 | 2026-11-07 | `mo clean` removed `~/Library/Caches/camoufox`, the default Camoufox install holding its browser binaries and version.json, so every Camoufox tool failed until a 1.3 GB re-download (#1941) | unknown | 68b1779c | unit | `should_protect_path applies high-risk cleanup denylist` |
| I-43 | 2026-11-08 | An unreadable `purge_paths` file looked like an empty configuration, so `mo purge --paths` or `mo purge --dry-run` could discover different roots and overwrite the custom scan scope | unknown | ae5a6eb5 | unit | `purge refuses unreadable custom paths without replacing them with discovered roots`, `purge paths preserves custom paths when the editor makes the configuration unreadable`, `load_purge_config keeps signal statuses silent and reports other read failures` |
| I-44 | 2026-11-08 | A broken link, link loop or directory at `purge_paths` counted as a missing file, so even `mo purge --dry-run` ran discovery and replaced the link or wrote into the directory | unknown | 57f2f633 | review | `purge refuses a config path that is not a readable file without discovering or rewriting` |
| I-45 | 2026-11-08 | `mo clean` removed `~/Library/Caches/Cypress`, the default Cypress install holding its test runner binary, so every Cypress run failed until a re-download of about 640 MB or more (#1945) | unknown | e0fc29d1 | unit | `should_protect_path applies high-risk cleanup denylist` |
| I-46 | 2026-11-09 | `mo clean` treated any `*.bundle` within three levels of `Application Support/Claude` as the orphaned workspace VM once Claude Desktop was gone, and its 7-day age could not see writes inside the bundle | f0896d03 | 1f96c482 | review | `clean_orphaned_app_data treats only vm_bundles entries as the Claude VM`, `is_claude_vm_bundle_orphaned reads the age of the files inside the bundle`, `orphan cleanup guard rechecks the Claude VM age at the final sink` |
| I-47 | 2026-11-09 | `mo clean` judged orphaned caches, logs and saved state by the directory's own mtime, so a folder whose files were still being written could read as 30 days idle and be removed | unknown | ac7e4f71 | review | `is_bundle_orphaned reads the age of the files inside the directory`, `orphan cleanup guard rechecks the age of a bundle's files at the final sink` |
| I-48 | 2026-11-08 | `mo clean` removed `~/.cache/puppeteer`, where Puppeteer installs its browsers by default, so the next launch failed with `Could not find chrome-headless-shell` until a re-download (#1941) | 5a8d7666 | 4cd5be26 | unit | `clean_browsers calls expected cache paths`, `should_protect_path applies high-risk cleanup denylist` |
| I-49 | 2026-11-08 | An existing `purge_paths` with no active line read as a missing file, so even `mo purge --dry-run` ran discovery and replaced the user's comments (#1953) | unknown | bb9dc526 | unit | `a config with no active paths uses defaults without discovering or rewriting (#1953)` |
| I-50 | 2026-11-09 | `mo analyze` read `unknown` for a readable `~/Library` or `/Applications` when one `du` passed 30 seconds, with no fallback after that deadline (#1956) | d04453f1 | d44c9f5f | field | `TestOverviewMeasurementOutlastsThePerFolderDuTimeout`, `TestOldDownloadsRowOutlastsThePerFolderDuTimeout`, `TestQuittingKillsARunningOverviewDu` |
| I-51 | 2026-11-09 | `mo purge` read a running project as idle when its path held a non-ASCII byte or a backslash, because purge runs under `LC_ALL=C` where lsof spells those bytes differently, and hid the `node_modules` of the project it was started from, because Mole's own shell and polling children counted as the project running | 52c5a7fa | c73bb7c9 | unit | `purge node project process check sees a real process in a non-ASCII project under LC_ALL=C`, `purge node project process check sees a real process in a path holding a backslash`, `mo purge run from inside a project still offers that project's node_modules` |
| I-52 | 2026-11-09 | `mo purge` offered and removed a build folder a running process still held, because only `node_modules` had a process check, so an in-use `dist`, `target` or `.venv` read as idle (#1958) | unknown | 6f2c0ce5 | review | `purge_artifact_in_use sees real holders above fd 999 and on non-ASCII paths`, `purge final sink refuses any artifact with open files and removes it once closed`, `purge dry run and real run refuse an in-use artifact the same way` |
| I-53 | 2026-11-09 | `mo clean` in a shell that could not write removed nothing, yet printed Cleanup complete, Removed: 0B and exited 0, so an agent read a clean that did nothing as a clean that ran | unknown | bab30aa8 | field | `mo clean refuses a shell that may not write, and removes nothing`, `mo clean still runs on a full disk, where the write check also fails` |
| I-54 | 2026-11-09 | `mo uninstall` in a terminal without Full Disk Access ran `du` on other apps' containers, which raised the access prompt and blocked the preview until it was answered | 85162c24 | 157296a6 | e2e | `without Full Disk Access, other apps' container rows are listed unmeasured`, `a whole uninstall never runs du on another app's container without Full Disk Access`, `a PlayCover app inside its container is not measured without Full Disk Access` |
| I-55 | 2026-11-10 | `mo clean --external` stopped at the first AppleDouble `._*` file that could not be sized, so the rest of the volume was neither previewed nor cleaned and the run ended incomplete (#1965) | b6ebce7a | cabffdb6 | write-time | `external cleanup continues when an AppleDouble metadata file size check fails`, `external cleanup continues when an AppleDouble metadata file size check times out` |
| I-56 | 2026-11-10 | `mo status --json` reported every Bluetooth device as disconnected, because `system_profiler` groups devices under `Connected:` headers and the parser looked for a per-device `Connected: Yes` line (#1967) | unknown | f2dbe843 | unit | `TestParseSPBluetoothReadsConnectionStateFromGroupHeaders` |
| I-57 | 2026-11-10 | `mo status` never reported memory pressure: `memory_pressure` prints no level name, so the field stayed empty and the health score and diagnosis never reacted to it (#1963) | 45d31e88 | f74d57f5 | e2e | `TestGetMemoryPressureReadsKernelLevel`, `TestParseMemoryPressureLevel` |
| I-58 | 2026-10-31 | `mo analyze` abbreviated HOME by string prefix, so with HOME `/Users/test` the sibling `/Users/tester/Downloads` was shown as `~er/Downloads`, a path that does not exist (#1892) | unknown | 8d02546b | unit | `TestViewHeaderKeepsSiblingOfHomeUnabbreviated` |
| I-59 | 2026-11-02 | `mo status` merged two different disks that had the same capacity into one row (#1900) | unknown | d3ae280e | unit | `TestCollectDisksDeduplicatesByDevice` |
| I-60 | 2026-11-02 | `mo status` on a short terminal clipped the dashboard from the top and hid the CPU heading (#1904) | unknown | 275036d6 | unit | `TestStatusRendererShowsHeightFallback`, `TestStatusViewFitsShortViewport` |
| I-61 | 2026-11-05 | A hand-written `timeout` shim on PATH reported its deadline as 143, so every bounded scan read as Ctrl-C and `mo clean` cancelled the rest of the run at the first slow scan (#1930) | unknown | 34b0fc06 | field | `timeout.sh skips a PATH timeout shim that reports its deadline as 143`, `timeout.sh keeps a PATH timeout that supports the wrapper arguments` |
| I-62 | 2026-11-07 | A PATH `timeout` shim passed the deadline-only probe but failed every real call, because `run_with_timeout` always passes `-k 2` (#1934) | 34b0fc06 | e6120d1d | write-time | `timeout.sh skips a PATH timeout shim without kill-after support` |
| I-63 | 2026-11-09 | `mo clean` deleted Buzz's downloaded Whisper models, installed plugins and presentation CSS, which the app keeps under `~/Library/Caches/Buzz` (#1950) | unknown | 67975fdc | field | `the user cache sweep keeps Buzz models and plugins even with a custom whitelist` |
| I-64 | 2026-11-10 | Seven test-only environment seams that choose a cleanup root, two of them deleted through sudo, were honored in real runs, so an exported `MOLE_XCODE_*`, browser bundle list or external volumes root redirected what `mo clean` removed | unknown | 2ed8427b | review | `test-only cleanup root overrides are read only through the test-mode guard`, `Xcode root overrides are honored only in test mode`, `browser and external volume root overrides are honored only in test mode` |
| I-65 | 2026-11-10 | `mo uninstall` sent Buzz's `~/Library/Caches/Buzz` (Whisper models, plugins, user CSS) to the Trash as a disposable cache, after #1950 protected it for `mo clean` only | 67975fdc | 5cbe27b7 | write-time | `uninstall keeps cache-resident user data out of automatic removal` |
| I-66 | 2026-11-10 | `mo uninstall --with-data` preselected the UTM container and VirtualBuddy's Application Support folder, which hold the virtual machine disks | unknown | 5cbe27b7 | review | `--with-data holds back UTM and VirtualBuddy virtual machine libraries` |
| I-67 | 2026-11-10 | `mo analyze` cut long CJK and flag names one cell wider than their column at some widths, pushing the size column | 8098ac2c | dfd0e583 | unit | `TestTruncateMiddleNeverExceedsTheColumnBudget` |