Development record
fsutil.RedactRoot and the scanner's home sweep still disagree on the LEADING boundary for a home of two or more segments under a longer root: SweepCallerHome sweeps '/Volumes/T7/srv/qzhome/x' to '/Volumes/T7~/x' (iss-324: a longer root does not make the name someone else's), while RedactRoot, and so RedactHome, the CLI error scrub and the install receipt, leave it whole because the byte before the root is a path-segment byte (iss-2609230641546141 chose that to stop '/private~/wt/a' mangles). The identity survives in CLI output wherever a message names a home under a backup volume or mount. Closing it needs a choice between the two rules for the '~' polarity (the '.' repo polarity has no counterpart); found while unifying the trailing half under iss-2608292037564347.
fsutil.RedactRoot and the scanner's home sweep still disagree on the LEADING boundary for a home of two or more segments under a longer root: SweepCallerHome sweeps '/Volumes/T7/srv/qzhome/x' to '/Volumes/T7~/x' (iss-324: a longer root does not make the name someone else's), while RedactRoot, and so RedactHome, the CLI error scrub and the install receipt, leave it whole because the byte before the root is a path-segment byte (iss-2609230641546141 chose that to stop '/private~/wt/a' mangles). The identity survives in CLI output wherever a message names a home under a backup volume or mount. Closing it needs a choice between the two rules for the '~' polarity (the '.' repo polarity has no counterpart); found while unifying the trailing half under iss-2608292037564347.
Evidence, 2026-09-29
The review of the trailing-boundary unification (iss-2608292037564347) found two further places where the redactors read a path differently. Both belong to the question this record already asks: should RedactRoot and the scanner's home sweep agree.
- The '.' repo polarity renders a suffixed repo root as a dot pair. Since 5d8bdc084 '.' ends a name, so a message naming the repo root with a trailing dot or a
.gitsuffix is redacted with the replacement's own '.' left in front of the suffix:fsutil.RedactRoot("see /Users/alice/proj.", "/Users/alice/proj", ".")returnssee .., andfsutil.RedactRoot("clone /Users/alice/proj.git now", "/Users/alice/proj", ".")returnsclone ..git now. Both read like a parent-directory reference. The redaction is the safe direction: the same probe at 5d8bdc084's parent returns both strings whole, leaking the full path. A fix is a choice of rendering for the '.' polarity, not of boundary. - On a case-folding host (macOS/APFS) the two redactors disagree on a case-variant home:
fsutil.RedactRoot("open /USERS/ALICE/a", "/Users/alice", "~")returnsopen ~/a, whilescanner.SweepCallerHome("open /USERS/ALICE/a", "/Users/alice")returns the string whole. RedactRoot folds case by design (iss-2608270908341622); the sweep does not, and whether the store's backstop covers the variant is unverified. This predates 5d8bdc084.
Probes: an external fsutil_test probe on a git archive copy of fix/drain-drift-2 at b8d69535c, and the same probe on a copy of 5d8bdc084's parent, both on darwin.
Remedy grounds (2026-09-29)
- Why: ruling BB's two answers, each with its change; it is unanswered and none is picked. The shared test is common to both, because the 2026-09-29 evidence shows the redactors already disagree on three inputs, not one.
- Rejected: fixing the dot-pair rendering or the case fold alone, which the record ties to the same ruling.
Frontmatter
| id | iss-2609290055092630 |
|---|---|
| type | issue |
| lifecycle | open |
| severity | minor |
.abcd/work/issues/open/iss-2609290055092630-fsutil-redactroot-and-the-scanner-s-home.md
open on GitHub ↗ · commit history ↗
mentions4
- iss-324scanner isPathSegmentByte includes the slash so a third partys home path inside a file URL escapes stage-one redaction
- iss-2608270908341622ahoy's home redaction tests HasPrefix(p, home+sep) case-sensitively, so a case-variant HOME spelling leaks the identity path in rendered output on a case-folding filesystem
- iss-2608292037564347v0.6.9 combined ruthless review: three sites carry the same path-boundary predicate in different polarities and now disagree on a trailing suffix. fsutil.isPathBoundary (internal/fsutil/paths.go) and scanner.isPathSegmentByte (internal/adapter/scanner/identity.go) are the same byte class inverted, and scanner.nameContinues (internal/adapter/scanner/residual.go) is the home-path anchor's rule — alphanumeric only. So fsutil.RedactRoot / RedactHome leave 'cannot access /Users/<user>.' untouched (the '.' is a segment byte to them) while SweepCallerHome sweeps it, and the CLI error scrub and the install receipt disagree with the store redactors about the same sentence. Proposal: one home for the predicate — fsutil exports the boundary rule, scanner imports it, and the alnum-only trailing rule is the shared definition — taken in its own pass because fsutil's callers (error scrub, receipts, RedactRoot) are a different set from the scanner's.
- iss-2609230641546141fsutil.RedactRoot (and so RedactHome and the CLI's error scrub) replaces a root that ends at a path boundary but never checks the boundary BEFORE it, so a root that appears as a suffix of a longer absolute path is redacted inside it: with HOME=/var/folders/x/T/home and git reporting the resolved /private/var/folders/x/T/home/wt/a, RedactHome returns /private~/wt/a — the prefix stranded in front of the tilde, and the path neither redacted nor intact. Seen while building the peer listing on macOS, whose temp dirs sit behind the /var -> /private/var symlink; the peers surface works around it by redacting the resolved home spelling first (internal/surface/cli/peers.go redactHomePath). Expected: a match that does not start at the string's start or after a non-path character is left alone, the way the right-hand boundary already is.