Skip to content

Commit 22c1bcb

Browse files
committed
chore(agents): add actions/cache exclude and target-shell testing rules
Two lessons from the hippolytus release-artifact work: - Every `!` exclude on an actions/cache path was a no-op for years, silently shipping stale bundles in every release. resolvePaths globs with implicitDescendants:false and tars the result with --files-from and no --no-recursion, so tar recurses into the ancestor dirs and re-adds every "excluded" file. Verified against the shipped dist. - Testing a `shell: bash` step under the zsh Bash tool reported a false failure: zsh aborts on an unexpanded glob where bash passes it through.
1 parent 6aa75db commit 22c1bcb

1 file changed

Lines changed: 2 additions & 0 deletions

File tree

home/dot_agents/AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ These constraints are unconditional. Apply them without being asked.
1616
- **Diagnose from logs, not theory.** When investigating a failure (CI, runtime, hang, regression), the last lines of output before the failure are ground truth, not a guess based on which script's name matches your current hypothesis or which prior bug looked similar. If the visible log doesn't pin the cause, add a diagnostic and re-run rather than speculate further. When reporting findings, mark claims as observed ("log line N says X") versus suspected ("I think Y because…") and never let suspicion harden into assertion without evidence.
1717
- **Contradictory observations mean a bad instrument, not a new theory.** When two measurements of the same thing disagree (a value healthy at line N but "null" at line N+1, a passing run and a failing run of identical code), stop hypothesising and instrument the exact divergent reads side by side in one run; the discrepancy is the bug's address. Treat tool-reported metadata as suspect until verified: logcat's tid column is the logger thread, not the caller (log gettid() yourself), and addr2line on optimised binaries misattributes merged inlined frames, so confirm the throw/crash site with a direct probe before acting on it.
1818
- **When diagnosing CI, read the repo at the SHA the runner checked out.** Your working tree is not what CI ran: it can be stale by many commits, and the failing run is often triggered by a commit you have never fetched (a bot's release or merge commit is the common case). Reading a config, manifest, or lockfile at local HEAD then yields a value that contradicts the log and sends you hunting a phantom, or worse, concluding the log is wrong. The checkout step prints the exact SHA it landed on (`git log -1 --format=%H`); fetch that commit and read files with `git show <sha>:<path>`. When a file's contents disagree with what the log implies, suspect you are reading the wrong ref before you suspect the log.
19+
- **An `actions/cache` `!` exclude does nothing if an ancestor directory is also matched.** `resolvePaths` globs the `path:` input with `implicitDescendants: false` and hands the resulting list to `tar --files-from` with no `--no-recursion`, so tar recurses into every directory in that list. The `!` line does drop the file from the glob output, but its parent is still there, and tar puts the file straight back: `target/**` plus `!target/release/bundle/deb/*.deb` caches the .deb regardless. Never express "cache everything except X" this way, since `dir/**` guarantees an ancestor is matched; instead delete X after restore, or cache only the specific subdirectories you want. The failure is silent and can persist for years: verify by resolving the real patterns through `@actions/glob` and taring the result. Suspect this whenever cached build output reappears in artifacts that a clean build could not have produced.
1920
- **A quoted error string in a log is not proof the error fired.** CI runners echo the script before executing it (GitHub Actions prints the whole `##[group]Run` body, `echo "::error ..."` conditionals included, often ANSI-highlighted), so a line containing an error template may just be the source of an un-taken branch. Identify where the annotation was actually emitted (the bare `##[error] ...` line, or the failing command's own stderr) before naming a cause, not where the text merely appears. Mis-reading an echoed conditional as a fired error sends you fixing the wrong thing.
2021
- **When a project's prose and its enforcement disagree, the enforcement wins.** A skill, README, or comment can drift from the CI gate, linter, or schema that actually rejects your change (e.g. a documented file layout that a CI guard now forbids adding). Before following a documented process that touches generated or tool-owned files, confirm it against the mechanism that will gate the PR; if they conflict, satisfy the gate and fix the stale doc in the same effort.
2122
- **Make the failure reproduce without a human before iterating on fixes.** When verification needs a human round-trip (someone wearing a headset, clicking a UI, plugging in hardware), build an autonomous repro first: a self-test that runs the failing path at startup, auto-dismissal of interactive gates, retry loops around known-flaky launches, and a streamed log capture started before launch so rotation can't eat the evidence. Each fix-then-ask-the-human cycle costs minutes and goodwill; the harness pays for itself by the second iteration.
@@ -86,6 +87,7 @@ Always edit the source, not the deployed file. When updating any memory file: re
8687
- Prefer the smallest atomic command that completes the immediate next step. Do not chain concerns across policy boundaries.
8788
- Destructive or policy-sensitive actions should be isolated so intent is easy to inspect.
8889
- Do not check whether a directory exists before using it. Attempt the operation; create the directory if it fails.
90+
- **Test a command in the shell that will actually run it.** The Bash tool here is zsh, while CI `run:` steps are typically `bash -e`, and the two disagree in ways that fake a failure. zsh aborts on an unexpanded glob (`no matches found`, nonzero exit) where bash passes the pattern through literally, so a perfectly safe `rm -rf foo/*/bar` reports a false failure locally and tempts you to "fix" a command that was never broken. Run the real thing (`bash -c '...'` or `bash script.sh`) before concluding anything about a snippet destined for bash. Generally: when validating a snippet for another runtime, reproduce that runtime's semantics rather than trusting your interactive shell's.
8991
- On Windows, when admin rights are required, launch elevated commands with `Start-Process -Verb RunAs` instead of failing back to manual instructions.
9092
- On Windows, use the Bash tool (not PowerShell) for POSIX-style commands like `grep`, `find`, `head`, `tail`, and path operations that use forward slashes. Use PowerShell only when you need Windows-native cmdlets, `$env:` variables, or paths with backslashes that POSIX tools cannot handle.
9193
- On Windows, POSIX-style paths like `/tmp/...` resolve only inside the Bash tool. Native filesystem tools (read/edit/write/grep/glob in any agent harness) use Windows file APIs and need Windows-style paths (`C:\...` or `C:/...`). When a Bash command reports a canonical path (e.g. `Cloning into 'C:/Users/.../Temp/repo'`), use that path for subsequent tool calls; do not reuse the `/tmp/` shortcut.

0 commit comments

Comments
 (0)