oficina / docs Public

Two environmental traps in AGENTS.md: config.lock, and pipes

Both cost time landing 1b6d392, both are permanent properties of this
environment rather than bugs in anything, and both are the shape the
section they join exists for — a step that cannot distinguish "no" from
"I can't see it".

**.git/config.lock is a read-only bind mount, not a stale lock.** I
recorded it as debris someone should clear; the paste-fidelity session
checked and corrected it, and /proc/mounts agrees: it is mounted
`ext4 ro,...` and `rm` answers "Device or resource busy". It is the same
mechanism .gitignore already documents for .gitconfig and .bashrc.

The consequence worth writing down is not "config is unwritable", it is
the partial completion: `git checkout -b` updates the index and working
tree and THEN fails on the config write, leaving HEAD on the old branch
with the new base's content in the tree. A branch you have been working
on looks like it has lost every change. Nothing is lost if it is
committed, but the first reading is that the tool ate your work — and
every session using `-b` without `--no-track` will meet it.

**A pipeline reports its last command's exit code.** Reading the gate
through `| tail` gives tail's 0 while a real failure scrolls past;
`amadan ci status | head` did the same while the command had failed
outright. The pipefail variant bites the other way: `strings | grep -q`
exits early, SIGPIPEs strings, and the pipeline is called failed — which
made a correctly version-stamped release binary read as unstamped.

Recorded here rather than in a discussion because neither is
branch-specific: they are true of every session in this repo, and the
section's own closing line is the argument for it — write it down rather
than resolving to be more careful, because care is not a mechanism.

Doc-only. This branch was created with `checkout -b --no-track`, which
is the fix the first entry prescribes, so it is at least self-consistent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WxucgadpWLE9XNWvfHBsnb
Paul Campbell pushed by paul@keymail.dev 3eb4452904c6cd54c047ec76ca634f747e2c3eb8 parent f5fd252
1 file changed, +38 −0
  • AGENTS.md +38 −0
diff --git a/AGENTS.md b/AGENTS.md
index b2580de..2f248ab 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -349,6 +349,44 @@ time in a single afternoon:
on the formatting-and-export branch, by a browser drive, after an
evening of looking at the wrong file.
+- **`git checkout -b` in this repo fails *after* rewriting your working
+ tree, and `.git/config.lock` is why.** That file is not a stale lock
+ left by a crashed process — it is a permanent read-only bind mount the
+ harness materialises (`/proc/mounts` shows it as `ext4 ro,...`; `rm`
+ answers "Device or resource busy"), the same mechanism `.gitignore`
+ already documents for `.gitconfig` and `.bashrc`. It makes git *config*
+ unwritable while the rest of `.git` stays writable. **No session can
+ clear it and none should try.**
+ So every git operation that writes config fails, permanently, and the
+ dangerous one is `git checkout -b <new> <base>`: it updates the index
+ and the working tree, *then* fails on the config write for upstream
+ tracking. HEAD stays on the old branch while the tree holds the new
+ base's content, so a branch you have been working on appears to have
+ lost every change, as deletions. Nothing is actually gone if it is
+ committed — `git reset --hard <sha>` puts it back — but the first
+ reading is that the tool ate your work.
+ **Always `git checkout -b <new> --no-track <base>`, and never
+ `git push -u`** (the push succeeds and then reports "unable to write
+ upstream branch configuration"; plain `git push origin <branch>` is
+ the shape). `--no-track` is not a workaround here, it is the permanent
+ spelling. The "unable to get credential storage lock … Read-only file
+ system" on fetch and push is the same family and is not worth chasing.
+ *(Found 2026-09-03 while landing the triage branch; diagnosed as a
+ bind mount by the paste-fidelity session after I had written it down
+ as debris someone should clear, which was wrong.)*
+- **A pipeline hides the exit code of everything but its last command.**
+ `bash .amadan/ci.d/10-gate | tail -40` reports `tail`'s status, which
+ is always 0, so a real failure scrolls past inside output you have just
+ read while the harness says success. Same for `amadan ci status … |
+ head`, which read as exit 0 while the command had actually failed with
+ "not an amadan remote". Run the thing, capture its status, then read
+ the log: `bash .amadan/ci.d/10-gate > gate.log 2>&1; echo "EXIT=$?"`.
+ The `set -o pipefail` variant of this bites in the opposite direction:
+ `strings "$bin" | grep -q "$sha"` exits early on a match, SIGPIPEs
+ `strings`, and pipefail then calls the pipeline failed — so a release
+ binary that *was* correctly version-stamped read as unstamped. Count
+ into a variable instead of using `grep -q`.
+
The shape to watch for is a verification that cannot distinguish "no" from
"I can't see it". When you catch one, write it here rather than resolving
to be more careful — care is not a mechanism.