This is the record of an abcd-managed repository

abcdBetav0.16.2 · 2026-11-06

Development record

2026-08-02 — iss-170: `resolvePluginRoot` now canonicalises the executable path with `resolvePath` (EvalSymlinks, falling back to `filepath.Abs`, then the original path, on error) before the ancestor walk, because `os.Executable` reports the path abcd was INVOKED through and `ahoy install` itself pins a PATH symlink at `/usr/local/bin/abcd` -> `<plugin-root>/abcd` — so the walk climbed the symlink's ancestors (`/usr/local/bin`, `/usr/local`, `/usr` — the loop's own guard excludes `/`, so it was never actually a candidate) and never saw `hooks/`, a permanent "plugin root not resolvable" gap on exactly the layout the installer writes, in a normal shell where neither `ABCD_PLUGIN_ROOT` nor `CLAUDE_PLUGIN_ROOT` is set (`CLAUDE_PLUGIN_ROOT` is set by the harness inside hook invocations, which is why every env-driven test — each of which sets it directly via `t.Setenv` — passed over the defect; this codebase has no independent evidence for whether any other context also sets it). The gap is platform-specific: `os.Executable` resolves through `/proc/self/exe` on Linux, already symlink-free, so the defect and this fix both bite only where the OS returns the invoked (unresolved) path — macOS's `execve`-argument implementation, per Go's `os/executable_darwin.go`. Reusing the existing `resolvePath` rather than calling `filepath.EvalSymlinks` inline keeps the fallback chain shared with the symlink-classification path; the `Abs` middle step is CWD-dependent in principle, but `os.Executable` returns an absolute path whenever it reports no error on both shipped platforms, so that step never fires here and no case that worked before can regress. Testing it required a seam: `os.Executable` is not overridable, so a package-level `var osExecutable = os.Executable` was added and the detector substitutes a fake returning the symlink path, with both env candidates blanked via `t.Setenv` so ONLY the fallback runs — watched fail (no plugin root) with the seam in place but the walk unresolved, and pass after.

decisiondcn-2608020000000002

2026-08-02 — iss-170: resolvePluginRoot now canonicalises the executable path with resolvePath (EvalSymlinks, falling back to filepath.Abs, then the original path, on error) before the ancestor walk, because os.Executable reports the path abcd was INVOKED through and ahoy install itself pins a PATH symlink at /usr/local/bin/abcd -> <plugin-root>/abcd — so the walk climbed the symlink's ancestors (/usr/local/bin, /usr/local, /usr — the loop's own guard excludes /, so it was never actually a candidate) and never saw hooks/, a permanent "plugin root not resolvable" gap on exactly the layout the installer writes, in a normal shell where neither ABCD_PLUGIN_ROOT nor CLAUDE_PLUGIN_ROOT is set (CLAUDE_PLUGIN_ROOT is set by the harness inside hook invocations, which is why every env-driven test — each of which sets it directly via t.Setenv — passed over the defect; this codebase has no independent evidence for whether any other context also sets it). The gap is platform-specific: os.Executable resolves through /proc/self/exe on Linux, already symlink-free, so the defect and this fix both bite only where the OS returns the invoked (unresolved) path — macOS's execve-argument implementation, per Go's os/executable_darwin.go. Reusing the existing resolvePath rather than calling filepath.EvalSymlinks inline keeps the fallback chain shared with the symlink-classification path; the Abs middle step is CWD-dependent in principle, but os.Executable returns an absolute path whenever it reports no error on both shipped platforms, so that step never fires here and no case that worked before can regress. Testing it required a seam: os.Executable is not overridable, so a package-level var osExecutable = os.Executable was added and the detector substitutes a fake returning the symlink path, with both env candidates blanked via t.Setenv so ONLY the fallback runs — watched fail (no plugin root) with the seam in place but the walk unresolved, and pass after.

Frontmatter

iddcn-2608020000000002
typedecision
date2026-08-02

mentions1