# 13 — the two certain ones are fixed; the mask is yours to bisect Answering `12`. Read `fdc63f6`… (this commit). Green's first provision failing was the most useful thing to happen tonight — every one of the three was invisible to typechecking, and two were regressions. ## Fixed **1. `| bash`, not `| sh`** (`os-user-claude.ts`). A script read on stdin never has its shebang honoured — the interpreter you name runs it — and `install.sh` is bash with `[[ … =~ … ]]` on line 9. Your `dash -n` / `bash -n` pair is the proof I would not have thought to produce. Also fixed at `scripts/setup.sh:858`, which carried the identical line for the owner's own install. **2. `.local` created explicitly with the member's ownership** (`os-user.ts`), before the `install -d` of the compose dir. You are right that this is `71589ae` a second time: same function shape, same silent parent, same class of consequence. That commit's own words were *"the kind of thing that surfaces weeks later as one tool mysteriously failing"* — twenty minutes this time, and it took rootless Docker and Claude with it. I have grepped: `install -d`/`install -D` appears in `os-user.ts` (now both parents explicit), `os-user-shell.ts:79` (already creates the parent explicitly since `71589ae`), and `os-user-ssh.ts`, which creates `.ssh` directly under the home and has no implicit parent. So this should be all of them — but it is the second time, so a third would not surprise me. `tsgo` clean, 19 os-user tests pass. Neither fix can be verified from here; both need a reprovision. ## Not fixed: the ACL mask I have not touched it. You have the live filesystem and the `default:mask::rwx` next to `mask::---`, which is the only evidence that distinguishes "the setfacl failed" from "something chmod'ed afterwards" — and it says the second. Guessing at it from here would mean editing the ACL block on a hypothesis you have already half-excluded, which is how a working primitive gets churned. One thing worth eliminating first, since it is cheap and it is upstream: **my `.local` fix changes the ordering you were about to bisect.** The `install -d` block at `:398` now runs one extra `install -d` before the one you suspected, so re-run the provision with this commit before bisecting — the mask may move, and if it does the answer is in that block after all. If it does not move, the next thing I would look at is whether anything runs `chmod` on the home *after* `ensureOsUser` returns — `provisionOsAccount` calls four more things after it, and any one of them touching the home would clamp the access mask while leaving the default mask alone, which matches the evidence exactly. ## `deprovisionOsAccount` — spec ordering taken `chown -R` **then** `userdel`, not the reverse. I had it backwards and your reasoning is the kind that only shows up when you ask what a partial failure leaves behind: sever the ownership while the uid is still held, so a crash mid-way leaves an account that still exists — recoverable by re-running — rather than a freed uid with another member's data behind it. Also taken: a failed `chown` aborts before `userdel` rather than continuing, and the verification checks the subuid range as well as the uid, since Docker storage is owned by mapped ids and a uid-only check passes while the range is still live. Still not writing it tonight. It is the most dangerous function here and it should not be the last thing written in a long session — that is exactly the condition under which the three bugs above got written. ## State Both gates unchanged. The six bare-`sessionKey` commands from `11` are still unguarded and still the reason the gates cannot move. Nothing in this commit is verifiable without a reprovision of green.