# Changelog 2026-07-10 -- ledger-scan.sh: self-inflicted next-free false positive (DOCFIX-174)

No live infrastructure touched. Found while preparing to assign the next real
DOCFIX number for follow-up work: `bash scripts/ledger-scan.sh` reported
`DOCFIX: highest=1004  next-free=1005` -- clearly wrong, since the repo is at
DOCFIX-173 (confirmed via `git log`).

## Root cause

Ironic: DOCFIX-173's OWN changelog
(`docs/changelog-20260710-sweep-script-fixes.md`) narrated a bug reproduction
for the `{3}` -> `{3,}` regex widening it was making, and used a literal
illustrative example -- the text `"DOCFIX-1004"` -- to demonstrate the OLD
bug's truncation behavior. `nextfree_mentions()` in `scripts/ledger-scan.sh`
greps ALL prose under `docs/` and `runbooks/` for the `DOCFIX-[0-9]{3,}`
pattern (excluding only lines that look like "next-free" pointers) and takes
the highest number found. The just-widened `{3,}` regex now matched that
illustrative "1004" as if it were a real assignment, inflating next-free from
174 to 1005. The very sweep that fixed one false-negative (numbers going
blind at a digit-count boundary) created a false-positive of the opposite
kind one commit later.

Confirmed via reproduction: `grep -rhoE 'DOCFIX-[0-9]{3,}' docs runbooks | grep
-viE 'next[- ]free' | sort -u` lists DOCFIX-173 as the true highest real
mention, plus the single spurious DOCFIX-1004 from the changelog's own prose.

## Fix

1. Reworded the illustrative example in
   `docs/changelog-20260710-sweep-script-fixes.md` to describe the
   reproduction in words instead of spelling out a literal
   `DOCFIX-<digits>`-shaped string, removing the false match at its source.
2. Made the identical edit to `scripts/ledger-scan.sh`'s own comment (which
   had the same literal string in a code comment -- not itself scanned since
   `scripts/` isn't a scanned directory, but worth fixing for hygiene so it
   isn't copy-pasted into a doc later).
3. Hardened `nextfree_mentions()` itself: consolidated the (accidentally
   duplicated, see Verification below) function definition into one, and
   added a second exclusion alongside the existing "next-free" pointer-line
   filter: lines matching `reproduc` (case-insensitive) are now also
   excluded from the mention scan. This is defense-in-depth, not a
   substitute for #1/#2 -- this repo's own delivery discipline narrates bug
   reproductions constantly ("Reproduced:", "confirmed-via-reproduction"),
   so a future sweep changelog doing exactly what DOCFIX-173's did is a
   real, recurring risk, not a one-off.
4. Added a regression fixture to `tests/ledger-scan/run-tests.sh`: a
   `docs/repro-example.md` file containing a "Reproduced: ... DOCFIX-1004
   ..." line, asserting the DOCFIX next-free assertion (`next-free=086`)
   still holds with that fixture present -- so this exact class can't
   regress silently again.

**Process note on how this was caught:** not by review -- by simply running
`bash scripts/ledger-scan.sh` before assigning the next real DOCFIX number for
unrelated follow-up work, and noticing the output was implausible (a jump from
173 to 1004) rather than trusting it. Same "verify before trusting a tool's
own output" discipline this session used repeatedly elsewhere (the
`expect_ok` dead-code bug, the `phase-06-capi-stack.sh` `PIPESTATUS` fix).

## Verification

`bash tests/ledger-scan/run-tests.sh`: 37/37 PASS (up from 33/33 -- one new
regression fixture + its assertion). `bash scripts/ledger-scan.sh`: now
correctly reports `DOCFIX: highest=173  next-free=174`. `bash
scripts/repo-lint.sh`: 0 fail, 1 documented legacy warn. Full gauntlet
(`bash scripts/run-tests-all.sh`): re-run after this fix, same pre-existing
environment gaps as every prior check tonight, zero regressions (see this
delivery's companion session-ledger entry for the exact count).

While editing, also caught and fixed my own mistake mid-fix: the first pass
at hardening `nextfree_mentions()` left TWO definitions of the function in
the file (the original, unedited one at its original location, plus a new
one with the fix inlined just before the call sites) -- a duplicate that
would still have worked (bash uses the last definition) but was sloppy and
would have confused the next reader. Caught by re-reading the file before
running the harness, consolidated to one definition in place.

REVERT: `git checkout HEAD~ -- scripts/ledger-scan.sh
tests/ledger-scan/run-tests.sh
docs/changelog-20260710-sweep-script-fixes.md` (safe -- no live infrastructure
depends on this script's output; it is a reporting/reconciliation tool only).

## Next actionable step

None required by this fix alone. The true next-free numbers going into any
follow-up work tonight are: D-111, DOCFIX-175, BUNDLEFIX-012 (this delivery
consumes DOCFIX-174).
