From 10bfd5074ab3352a56510aabb3815eb89613a9ac Mon Sep 17 00:00:00 2001 From: gogocat Date: Tue, 8 Sep 2026 14:26:37 +0300 Subject: [PATCH] docs(agents): give findings a home, and say which one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A finding that lives only in a reply is gone at the end of the session. That has cost real work here twice: a 465-artifact measurement that cancelled a planned fix existed only in chat, and a handoff document pointed at a scratch directory that did not outlive the session. Three kinds of finding, three homes: a behaviour-changing rule goes in this file, work goes in an open issue, and a measured dead end goes in an issue closed on arrival under the new `measured-not-planned` label. The third is the one that pays. A measurement that CANCELS work is worth as much as one that starts it and evaporates faster, because nobody files "we checked and it does not matter" — so the next person re-derives it. #476 is the worked example. Every filing carries a trigger phrased as a condition, not a date, and the revisit is a step in the release flow rather than a habit nobody has. Also records two mechanics that silently do nothing: `Closes #N` is inert when merging into `dev` because GitHub honours it only on the default branch, and an empty `gh` result can be a GraphQL EOF rather than an absence. Plus the zsh `PIPESTATUS` trap, filed with the disk-full family it belongs to — the exit code is real, it is just measuring `tail`. Refs: #476 --- AGENTS.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 2635d755..7d3ff612 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -92,6 +92,68 @@ Two related traps, same family: for anything that writes. A concurrent commit from a second session has already cost a lost commit-message file and half an hour of misdiagnosis in this repo. +- **The exit code you print through a pipe is the wrong one.** `cmd | tail` and + `echo $?` reports `tail`. `${PIPESTATUS[0]}` is a bashism and expands to the + empty string in this repo's zsh, so the guard prints `exit=` and reads as + fine. Redirect to a file and measure without a pipe: + `cargo clippy ... > /tmp/x.log 2>&1; echo "exit=$?"`. Same family as the + disk-full trap above — the number is real, it is just measuring something + else. + +## Findings have a home, and it is not the chat + +A finding that lives only in a reply is gone at the end of the session. This has +already cost real work here: a measurement across 465 artifacts that cancelled a +planned fix lived nowhere but a chat message until someone thought to file it, +and a handoff document once pointed at a scratch directory that did not survive +the session it described. + +**File it the moment you find it, before finishing the thought that produced +it.** Three kinds of finding, three homes: + +| Finding | Home | Why there | +|---|---|---| +| A rule that changes how an agent works | **this file** | Read every session. Costs context every session, so it earns its place only by changing behaviour. | +| Work someone should do | **GitHub issue**, open | Assignable, closable, outside the context budget. | +| A measured dead end — checked, decided not to do | **GitHub issue, closed on arrival**, label `measured-not-planned` | Findable by `gh issue list --state closed --label measured-not-planned`. Costs nothing to keep. | + +The third row is the one people skip, and it is the one that pays. A measurement +that **cancels** work is worth as much as one that starts it, and it evaporates +faster — nobody files "we checked and it does not matter". Then the next person +smells the same thing and re-derives it. #476 is the worked example: two +plausible defects, both measured, both left alone, numbers on the record. + +Rules for filing: + +- **Numbers, not adjectives.** "Zero verdicts change across 465 artifacts" + survives a year. "Seems fine" does not. +- **Every finding carries a trigger to revisit, phrased as a condition.** + `"later"` is not a trigger. `"if stripping comments would change the verdict + on one or more artifacts"` is. Same rule ADRs already follow: name what must + become true for someone to pick this up. +- **Say what was rejected and why.** A finding that records only the conclusion + invites the next person to relitigate the option you already killed. +- **Do not file the same thing twice.** `gh issue list --search` before + creating; extend the existing issue if one fits. + +Revisit is a step, not a habit: **before opening a `release/v*` PR**, list the +`measured-not-planned` issues and re-check their triggers against the current +corpus. A trigger that has become true reopens the issue; one that has not gets +left alone without discussion. + +## GitHub mechanics that silently do nothing + +- **`Closes #N` in a PR body does not close anything when merging into `dev`.** + GitHub honours closing keywords only on merges into the *default* branch, and + ours is `main`. Feature branches merge into `dev`, so the keyword is inert and + the issue stays open with no error anywhere. Close the issue by hand at + dev-merge, naming the merge commit — leaving it open until the release means + the board says "nobody did this" about finished work. +- **An empty `gh` result is not proof of absence.** `Post + "https://api.github.com/graphql": EOF` prints nothing to stdout and can exit + through a pipe as success. Verify a listing you are about to act on by + querying the object directly, not by trusting that zero rows means zero + things. ## Repository structure (quick map)