Ran the scan. Answer to your question: run it, hold the re-emit, and the reason is a regression in the fix itself.
Sample, and its bias first
1,878 of the 9,988 top-level data/*.jsonl, spanning A to z, size-capped: 98 MB against the corpus's 174 GB. Small-file biased, so no corpus-wide rate, as agreed. 22,773 rows, 0 bad JSON.
Sentinels in that sample: [PHONE] 33,198 across 915 rows, [EMAIL] 1,852 across 1,028 rows, [IP] 2,240 across 515 rows. 860 distinct source repos touched.
The class split is the part I did not expect
Split the 33,198 [PHONE] by which fix covers it:
lockfile-named rows (fix 1) 2,550 105 rows
pseudo-version v0.0.0-[PHONE]-<sha12> 2,436
... of those in NON-lockfile rows 10 2 rows
adjacent to a hex/base64 run (fix 2) 2,616
neither lockfile nor pseudo-version 30,638 809 rows
92% of the redactions sit outside both named classes. The top of that residue is numeric data, not code:
6,140 Statistical-Inference/Section6.2/female.csv
5,298 Statistical-Inference/Section6.2/male.csv
3,377 Turf.jl/test/geojson/route2.geojson
1,763 DiTox_v1/final_model/dataset_3090.csv
1,225 NMEA.jl/test/testdata.txt
1,000 advent-of-code-2021/day3/input.txt
695 Colormaps.jl/data/bright_viridis.py
female.csv is fractions of a day, 0.479166666666667. The AoC file is puzzle input. The geojson is a GPS track.
Then I ran your scrubber instead of reasoning about it
Pulled scripts/build_cogito_corpus.py at HEAD from peterlodri-sec/MLX-QUANT, loaded old and new scrub_text side by side, fed both the current upstream originals of 17 of those files.
Validation first: my replica of the old rule reproduces the shipped corpus [PHONE] count exactly on 17 of 17 files. 6,140 is 6,140, 380 is 380. So the deltas are trustworthy.
file OLD NEW
Statistical-Inference/.../female.csv 6,140 0
Statistical-Inference/.../male.csv 5,298 0
Turf.jl/test/geojson/route2.geojson 3,377 6,777
DiTox_v1/final_model/dataset_3090.csv 1,763 1,067
NMEA.jl/test/testdata.txt 1,225 0
advent-of-code-2021/day3/input.txt 1,000 0
jsondiff/testdata/examples/twitter.json 875 0
Colormaps.jl/data/bright_viridis.py 695 1
QuantileRegression.jl/examples/engel.csv 470 0
ContinualLearning/.../QuickDraw.py 430 0
SMTPClient.jl/test/send.jl 339 507
deanie/test/Model/Mixture.hs 324 0
CCBs_AAD/CCBs_AAD_code.R 252 0
go-cli-template/go.sum 380 0
ots/go.sum 303 0
bel/go.mod 2 0
Annotation-Factory/README.md 2 0
TOTAL 22,875 8,352
Net minus 63%, and the win comes mostly from fix 2's mandatory separator, not from the lockfile exemption. Bigger than the fix was aimed at.
Two files go the wrong way, and that is what blocks the overwrite
route2.geojson goes 3,377 to 6,777. New is a strict superset there: 3,400 matches added, zero removed.
new catches, old did not: 49.724758 49.698135 45.992548 49.785468
old already caught: 113.928988 113.928993 113.929029 113.951995
Longitude was already dying. Now latitude dies with it, so the whole coordinate pair goes instead of half. send.jl moves 339 to 507 the same way, 432 added and 298 dropped.
The mechanism lives in the same edit that fixed go.sum. Old was \b\+?[0-9]{1,3}[ .-]?...\b. New made the separator mandatory, which is exactly what kills the bare 14-digit timestamp, but it also dropped the leading \b and widened the lead to [0-9]{2,4}. So NN.NNNNNN now matches where only NNN.NNNNNN did.
So, concretely
Run the scan. Hold the re-emit until the delta is signed per file, because "overwrite in place" is only safe while new is a subset of old, and on the numeric class it is not. One guard does it: re-emit a file only when its new sentinel count is at or below its old count, and route the rest to a held list. That turns your before/after delta table into a gate rather than a report.
And 8,352 remain in the sample after the fix, so the numeric class does not reach zero either way.
Which raises the question I keep circling. You exempted lockfiles by filename because a checksum-per-line file has no PII to protect. A .geojson of coordinate pairs, or a CSV of pure numeric columns, has the same property and no shape rule will ever see it. Is the extension the wrong hook, or is the real signal the column, that a file where every token on the line parses as a float is not a file where a phone number can hide?