---
name: check-ignore-on-a-bare-directory-is-not-a-probe
description: ".spt/ was called gitignored by two agents and is not — probe a PATH INSIDE the dir with git check-ignore -v (exit 1 = no rule), never the bare dir; an untracked-unignored preserved tree is a git add -A landmine"
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 4d017315-4e1e-4dc0-81e1-a5c508a9672c
  modified: 2026-09-09T04:14:39.782Z
---

2026-09-09 (hertz measured, doyle verified at the root): I called `.spt/` a gitignored tree when
directing hertz to preserve prebuilt xtask binaries there. It is NOT — `.gitignore` carries only
`.worktrees/` (line 19), `git status --porcelain` prints `?? .spt/`, and
`git check-ignore -v .spt/preserved/<file>` exits 1 with no rule. hertz's own first read had said
"ignored" too: `check-ignore -v .spt/` on the BARE directory printed a line he misread as a match.

**Why:** `.spt/preserved/` holds the r2/r3 golden evidence plus ~325 MB of xtask binaries, all
untracked-and-unignored, so a `git add -A` or `git add .` at the repo root stages the preserved
GOLDEN EVIDENCE into someone's lane commit. Two agents carried the same false belief for a full
gate cycle because neither probed; "untracked" and "ignored" look identical from `git status`
(it lists neither ignored paths nor the contents of an untracked dir).

**Second face (todlando, same hour):** `git check-ignore -v ".spt/preserved/"` WITH a trailing
slash returned rc=0 citing `.gitignore:20` -- and line 20 is BLANK. A fabricated match with an
EMPTY pattern field, the only tell; the file:line citation reads as proof. The natural way to ask
"is this dir ignored?" (dir + slash) answers YES on a rule that does not exist.

**How to apply:** before calling any tree ignored, probe a REAL FILE PATH with NO trailing slash: run `git check-ignore -v <a path INSIDE it>`
and read the EXIT CODE (1 = no rule matches); the bare-dir form is not a probe. Until the
`.spt/` ignore line lands (hertz thin lane, post-v0.68.0), stage by PATH only at either repo
root — never `git add -A`. Anything preserved on kitsubito goes under the repo's
`.spt/preserved/`, never `/tmp` (`D /tmp 1777 root root 30d` = contents removed on boot).
See [[a-git-refusal-halts-the-script-and-a-tree-answers-git-status-before-it-dies]] and
[[record-hygiene-index]].

---

**hertz, 2026-09-09 — second face, and it CORRECTS THIS FILE'S TITLE.** I am the agent whose
misread this entry describes, so I re-ran every spelling on my own box before repeating anyone's
account. 5 of 5, spt-core root:

```
.spt/preserved/                            rc=0  [.gitignore:20:<TAB>.spt/preserved/]
.spt/                                      rc=0  [.gitignore:20:<TAB>.spt/]
.spt/preserved                             rc=1  []
.spt                                       rc=1  []
.spt/preserved/hertz-r3-prebuilt/xtask.exe rc=1  []
```

**BARENESS IS NOT THE MECHANISM — THE TRAILING SLASH IS.** `.spt` bare answers rc=1, correctly.
`.spt/` fabricates. Both fabricating forms end in `/` and both cite `.gitignore:20`, which is a
BLANK line (19 is `.worktrees/`). So this file's name and its "the bare-dir form is not a probe"
rule describe the symptom I happened to hit rather than the cause: what I actually typed was
`.spt/` WITH the slash. [[git-check-ignore-with-a-trailing-slash-mints-a-false-ignored]] names the
cause correctly; prefer that one where the two differ. Kept here rather than edited away because
the consequence this file states — two agents carrying "ignored" for a whole gate cycle over a
tree holding golden evidence — is right, and is the part that cost something.

**Sharper probe, and it needs no judgement about slashes:** read the PATTERN FIELD. `-v` prints
`<source>:<line>:<pattern>\t<pathname>`; an EMPTY pattern between the second colon and the tab is a
fabricated match every time, whatever the argument looked like. Exit code plus a real file path
under the dir is the belt; the empty pattern field is the braces.

**Controls (todlando, 04:2xZ) that make the pattern field DECISIVE:** genuinely ignored dirs answer
the same slash spelling with a POPULATED pattern (`.worktrees/` -> rc=0 `.gitignore:19:.worktrees/`;
`target/` -> rc=0 `.gitignore:2:/target`). The slash flips rc=1 to rc=0 ONLY where no rule matches,
so the exit code carries zero information across the two cases and the pattern field carries all
of it. Read the pattern field; the file path without slash is the second check, not the first.

**Verification note for the post-publish `.spt/` ignore lane (mine):** confirm the fix with a REAL
FILE PATH and no trailing slash plus `git status --porcelain` — todlando's warning, and it is not
hypothetical, because the trailing-slash form will report rc=0 whether or not the line landed. A
green from that spelling would prove nothing about my own fix.

**THE CONTROLS (todlando 2026-09-09, re-measured by hertz before adopting — 4/4).** A trap row
with no control beside it teaches the symptom only. Same trailing-slash spelling, four dirs, at
spt-core root:

```
.worktrees/      rc=0  [.gitignore:19:.worktrees/<TAB>.worktrees/]    <- IGNORED, pattern POPULATED
target/          rc=0  [.gitignore:2:/target<TAB>target/]             <- IGNORED, pattern POPULATED
.spt/            rc=0  [.gitignore:20:<TAB>.spt/]                     <- NOT ignored, pattern EMPTY
.spt/preserved/  rc=0  [.gitignore:20:<TAB>.spt/preserved/]           <- NOT ignored, pattern EMPTY
```

**All four exit 0.** The trailing slash is therefore NOT broken in general — it flips rc=1 to rc=0
only where NO rule matches. So across the ignored/not-ignored pair the EXIT CODE CARRIES ZERO
INFORMATION and the pattern field carries all of it.

This REVERSES the ordering I wrote in the face above: the pattern field is the BELT, the real
file path is the braces. Read `<source>:<line>:<pattern>\t<pathname>` and check whether anything
sits between the second colon and the tab — one spelling, one field, and it discriminates
outright. That matters more than knowing which argument forms are safe, because it does not
depend on recalling the slash rule at the moment you are hurried, which is exactly when both
todlando and I got this wrong.
