Development record
The plugin-root binary predates the verbs its own command surface documents, and the failure is an unknown-command error rather than a named refusal. Verified 2026-08-23: the commands/update.md page instructs the reader to run the plugin-root binary first, and that binary on this machine is v0.6.1, whose help lists no update verb at all. Running it as documented gives 'abcd: unknown flag: --yes', and running the bare verb gives 'abcd: unknown command "update" for "abcd"'. The page's own resolution ladder recovers the situation, since a source checkout falls through to go run ./cmd/abcd, but only for a reader who knows to keep going: the first rung produces an error that looks like a malformed invocation rather than a stale install. This refines iss-228, which records the same root cause with a different consequence -- a plugin-root binary sitting a month stale so ahoy's first resolution rung reported pre-iss-171 gaps with no staleness signal. That entry is about wrong gap reporting; this is about a documented command surface pointing at a binary that cannot serve it. The general shape is that the plugin surface and the plugin binary ship from one release but a repository checkout can be arbitrarily far ahead of the installed plugin, so every commands/*.md page documenting a verb newer than the reader's plugin has this failure mode, and update is merely the first to be noticed. Two directions, neither adopted: have the command pages degrade legibly when the resolved binary lacks the verb, by checking for it before invoking; or have the binary answer an unknown verb by naming its own version and vintage, so the error says stale rather than wrong. Worth deciding whether this is inherent to plugin-versus-checkout skew and therefore only a documentation problem, or whether the unknown-command path should carry install context.
The plugin-root binary predates the verbs its own command surface documents, and the failure is an unknown-command error rather than a named refusal. Verified 2026-08-23: the commands/update.md page instructs the reader to run the plugin-root binary first, and that binary on this machine is v0.6.1, whose help lists no update verb at all. Running it as documented gives 'abcd: unknown flag: --yes', and running the bare verb gives 'abcd: unknown command "update" for "abcd"'. The page's own resolution ladder recovers the situation, since a source checkout falls through to go run ./cmd/abcd, but only for a reader who knows to keep going: the first rung produces an error that looks like a malformed invocation rather than a stale install. This refines iss-228, which records the same root cause with a different consequence -- a plugin-root binary sitting a month stale so ahoy's first resolution rung reported pre-iss-171 gaps with no staleness signal. That entry is about wrong gap reporting; this is about a documented command surface pointing at a binary that cannot serve it. The general shape is that the plugin surface and the plugin binary ship from one release but a repository checkout can be arbitrarily far ahead of the installed plugin, so every commands/*.md page documenting a verb newer than the reader's plugin has this failure mode, and update is merely the first to be noticed. Two directions, neither adopted: have the command pages degrade legibly when the resolved binary lacks the verb, by checking for it before invoking; or have the binary answer an unknown verb by naming its own version and vintage, so the error says stale rather than wrong. Worth deciding whether this is inherent to plugin-versus-checkout skew and therefore only a documentation problem, or whether the unknown-command path should carry install context.
Grounds
- pursued: the command page beside the plugin root is evidence the binary itself can read, so an unknown verb whose page exists is expected to read as a stale install with its way out rather than a malformed invocation; a reader who still has to fall through the resolution ladder blind after a plugin update would show this wrong.
Frontmatter
| id | iss-2608230943088357 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2608230943088357-the-plugin-root-binary-predates-the.md
open on GitHub ↗ · commit history ↗
mentions7
- dcn-26102809052072022026-10-28 — The plugin's hooks and command pages run a build of the checkout's HEAD in a checkout the person lists in ~/.abcd.noindex/dogfood-roots, and the installed release everywhere else, because iss-2610070547057816 records that the person wants exactly that, so no question was put. It does not conflict with AGENTS.md's go run rule: that rule governs the agent's own invocations in a source checkout and leaves the surface half to iss-2608230943088357, which this change addresses for the hooks and command pages (facilitator on delegation, lane D, 2026-10-28).
- iss-171The PATH-install detector and installer assume one blessed layout: binTarget defaults to /usr/local/bin/abcd (sudo territory abcd cannot assume) and symlink detection only recognises that exact target, so a working ~/.local/bin/abcd symlink install — the field-standard single-user location used by uv/pipx/rustup-class tools — reports symlink.missing, a false gap; the detector is itself running as abcd from PATH while reporting abcd not installed. Letting ahoy install 'fix' it would write a symlink to <plugin-root>/abcd without validating the target exists — a dangling symlink shadowing the working install. Redesign per fix-the-detector and no-sudo: detection scans PATH for abcd, resolves symlinks (EvalSymlinks, same seam as iss-170), classifies dev-shim/owned/foreign; install defaults to ~/.local/bin (create if needed), adopts an existing owned install in place, does system-wide dirs only behind an explicit --bin-dir flag failing loudly when unwritable, never escalates privileges, refuses to create a symlink whose target does not exist; '~/.local/bin not on PATH' becomes its own loud gap with the printed one-line fix (script-first: print the export line, do not auto-patch shell profiles as the first rung).
- iss-228The plugin-root binary (repo-root abcd -> bin/abcd-darwin-arm64) sat a month stale after iss-171 merged, so the ahoy skill's first resolution rung reported pre-iss-171 gaps (wrong target, missing --bin-dir) with no staleness signal; the skill and detection have no guard that warns when the plugin-root binary predates the source tip in a source checkout
- iss-2609012028144617In a source checkout of abcd itself, the plugin-root binary and any abcd on PATH are the last published version, so they are stale by construction and fall further behind with every commit, and the failure is not always a refusal. Three hits in one session while cutting v0.7.0: launch ship refused on its surface guard, correctly and loudly; changelog --json returned an empty cut against a tree with 181 shipped records, no error, a plausible wrong answer briefly read as evidence about the release; and capture would have written records through a schema that predates the origin and production_mode disclosure pair the record gates now require. The plugin skill pages document a resolution ladder that reaches the plugin binary first and falls through to go run ./cmd/abcd only when nothing earlier resolves, and in this checkout the first rung exists and answers, so the fallback written for exactly this case is unreachable by following the ladder literally. The convention every agent in this repository needs is that every abcd invocation here is go run ./cmd/abcd from the repo root; it belongs in the committed record, in AGENTS.md and as a loader domain that fires on prompts naming an abcd verb, rather than in a per-machine handover note. Carried from the session handover into autonomous-run-2026-09-01; the skill pages' resolution order is the other half and stays with iss-2608230943088357.
- iss-2609020113012227Refines iss-2608230943088357, which main resolved for the two LOUD shapes (an unknown flag, an unknown command) by naming the stale binary in the refusal. This record carries the third shape, which is SILENT and which that fix cannot reach: the verb exists, is served by the old plugin root, and answers confidently. Observed 2026-09-01 immediately after the v0.7.0 release; the mechanism is that plugin roots are keyed by the commit they were installed from, so a hash-pinned path baked into a skill page is designed to expire, and the old root stays on disk ready to answer. The section that follows is the observation as recorded on the day.
- iss-2610141647314635A stale published abcd binary in a source checkout can answer a verb with a plausible wrong result instead of refusing: iss-2608230943088357 resolved only the refusal half (an unknown verb or flag now names the staleness), and the same binary reports 'staleness: up to date' when run outside a checkout, so the flag cannot warn a runner who resolves it from elsewhere (lab finding F-3).
- spc-2610170635097509after-update