Development record
abcd update calls a pinned install foreign when its symlink points into a superseded plugin-cache version. On this machine ~/.local/bin/abcd is the pin abcd ahoy install wrote on 2026-09-07: a symlink into the plugin cache directory of the v0.7.1 vintage (e3696dc524e3). After the plugin moved on, go run ./cmd/abcd update v0.9.0 --yes refused with 'the entry at ~/.local/bin/abcd is not something abcd owns, and abcd never clobbers a binary it does not own' and offered 'remove or rename the occupant' as the remedy. The link target is a published release binary (its digest is the darwin-arm64 line of v0.7.1's checksums.txt) inside abcd's own cache, so nothing about it is foreign: the classifier in internal/core/ahoy/update_target.go only admits a symlink into the CURRENT plugin root as owned, and a link into an older vintage falls through to foreign before the digest check the verb's help promises ever runs. The refusal's detail and remedy are both wrong for this shape; the right remedy is abcd ahoy install, which the owned-dangling case already names, and the honest detail is that the pin points at a superseded vintage. Found while finishing the v0.9.0 deploy on 2026-09-16.
abcd update calls a pinned install foreign when its symlink points into a superseded plugin-cache version. On this machine ~/.local/bin/abcd is the pin abcd ahoy install wrote on 2026-09-07: a symlink into the plugin cache directory of the v0.7.1 vintage (e3696dc524e3). After the plugin moved on, go run ./cmd/abcd update v0.9.0 --yes refused with 'the entry at ~/.local/bin/abcd is not something abcd owns, and abcd never clobbers a binary it does not own' and offered 'remove or rename the occupant' as the remedy. The link target is a published release binary (its digest is the darwin-arm64 line of v0.7.1's checksums.txt) inside abcd's own cache, so nothing about it is foreign: the classifier in internal/core/ahoy/update_target.go only admits a symlink into the CURRENT plugin root as owned, and a link into an older vintage falls through to foreign before the digest check the verb's help promises ever runs. The refusal's detail and remedy are both wrong for this shape; the right remedy is abcd ahoy install, which the owned-dangling case already names, and the honest detail is that the pin points at a superseded vintage. Found while finishing the v0.9.0 deploy on 2026-09-16.
Grounds
- pursued: the pin was written by abcd into abcd's own cache, so calling it foreign sent the operator to hand-delete their own install; owning the shape gives every surface the same remedy, and the git-checkout gate keeps a developer's deliberate sibling-build link untouched
Frontmatter
| id | iss-2609161805447092 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2609161805447092-update-calls-a-pin-into-a-superseded.md
open on GitHub ↗ · commit history ↗
mentions2
- iss-2609100506263330`ahoy install` can report success while leaving a PATH entry that a later plugin update silently breaks, and the condition that decides which happens is invisible to the operator.
- iss-2609120447482506PATH entry written as a symlink to the plugin-root binary (no verified artefact in the cache) is fragile by abcd's own note, yet bare 'ahoy' reports zero gaps afterwards. Immediately after a plugin update the symlink still pointed at the superseded root e3696dc while the live root was eda67ccc, and install_mode read 'pinned'. Detection should surface this as a gap (entry points at a non-current plugin root / not an owned copy) rather than only in a one-time install note; better still, provision the cache during install so the owned copy is written first time.