doctor cannot see a release the host has not fetched — clean at 0.12.1 while main is v0.13.0 #38

Closed
opened 2026-08-29 12:13:03 +00:00 by mathias · 1 comment
Owner

Residual gap in the check shipped for #30, found while verifying koala at the end of the backlog sweep.

What works

bin/doctor compares the version recorded in installed_plugins.json against the newest manifest already on the host — the active checkout plus any marketplace clone. On koala right now:

{"checkout":"/home/mathias/.local/share/skills","expected":41,
 "plugin":{"installed":"0.12.1","available":"0.12.1"},"findings":[]}

Correct, and it caught the real 0.6.0-vs-0.8.4 skew earlier today.

What it cannot see

v0.13.0 is the latest tag on main. This host is at 0.12.1 everywhere — checkout, marketplace clone, installed plugin — so all three agree and doctor reports clean. The host is one release behind and says nothing.

That is the same class of silence #30 was filed about, one level up: not "the plugin is older than the checkout" but "everything here is older than the repo".

Why it is not simply a bug

bin/doctor does no network I/O, deliberately — it runs in a SessionStart hook where latency shows, and its header says so: "It does no network I/O and never shells out to git for a fetch." Detecting this needs either a fetch or a cached answer from something that does fetch.

Options, none obviously right

  1. Leave it. task update fast-forwards and re-wires; the gap only bites a host nobody has updated. Costs nothing, catches nothing.
  2. Opt-in flag. doctor --online does one git ls-remote --tags and reports; the session hook keeps calling the offline form. Honest, but a check nobody runs by default is close to option 1.
  3. Cache the answer. Whatever already fetches on this host (the plugin's own update path, or a scheduled job) writes the latest known tag to a file; doctor reads it and reports staleness plus the file's age. Keeps doctor offline and still catches the case — but adds a second thing that can be stale, which is how this whole class starts.

Leaning 2, with the flag wired into a scheduled per-host job rather than into the session hook.

Also noticed

Something re-ran install.sh with the default SKILLS_CHECKOUT_DIR at 14:05 today, which fast-forwarded ~/.local/share/skills and re-pointed every link there, replacing the wiring an earlier task install had made from ~/dev/skills. That is arguably correct — the default is documented as load-bearing — but it means the canonical checkout on a host can move without anyone asking for it, and ~/dev/skills silently stops being what any harness loads. Worth confirming what ran it before deciding whether it is a feature.

Residual gap in the check shipped for #30, found while verifying koala at the end of the backlog sweep. ## What works `bin/doctor` compares the version recorded in `installed_plugins.json` against the newest manifest already **on the host** — the active checkout plus any marketplace clone. On koala right now: ```json {"checkout":"/home/mathias/.local/share/skills","expected":41, "plugin":{"installed":"0.12.1","available":"0.12.1"},"findings":[]} ``` Correct, and it caught the real 0.6.0-vs-0.8.4 skew earlier today. ## What it cannot see `v0.13.0` is the latest tag on `main`. This host is at `0.12.1` everywhere — checkout, marketplace clone, installed plugin — so all three agree and doctor reports clean. The host is one release behind and says nothing. That is the *same class* of silence #30 was filed about, one level up: not "the plugin is older than the checkout" but "everything here is older than the repo". ## Why it is not simply a bug `bin/doctor` does no network I/O, deliberately — it runs in a SessionStart hook where latency shows, and its header says so: *"It does no network I/O and never shells out to git for a fetch."* Detecting this needs either a fetch or a cached answer from something that does fetch. ## Options, none obviously right 1. **Leave it.** `task update` fast-forwards and re-wires; the gap only bites a host nobody has updated. Costs nothing, catches nothing. 2. **Opt-in flag.** `doctor --online` does one `git ls-remote --tags` and reports; the session hook keeps calling the offline form. Honest, but a check nobody runs by default is close to option 1. 3. **Cache the answer.** Whatever already fetches on this host (the plugin's own update path, or a scheduled job) writes the latest known tag to a file; doctor reads it and reports staleness plus the file's age. Keeps doctor offline and still catches the case — but adds a second thing that can be stale, which is how this whole class starts. Leaning 2, with the flag wired into a scheduled per-host job rather than into the session hook. ## Also noticed Something re-ran `install.sh` with the **default** `SKILLS_CHECKOUT_DIR` at 14:05 today, which fast-forwarded `~/.local/share/skills` and re-pointed every link there, replacing the wiring an earlier `task install` had made from `~/dev/skills`. That is arguably correct — the default is documented as load-bearing — but it means the canonical checkout on a host can move without anyone asking for it, and `~/dev/skills` silently stops being what any harness loads. Worth confirming what ran it before deciding whether it is a feature.
Author
Owner

Shipped in b2af4e1 — option 2, the opt-in flag.

task doctor -- --online     # or bin/doctor --online

One git ls-remote against origin. Belongs in a scheduled per-host job, not the SessionStart hook — a check that costs latency on every session start is a check someone eventually disables.

Design calls, each for a reason

Order, not equality. A host ahead of the newest tag is the normal state between a release commit and its tag landing. Same reasoning as task check's ordering rule (#34), reusing bin/newer-version.

An unreachable remote is a WARN naming itself, not a staleness FAIL. "I could not check" and "you are behind" are different answers, and collapsing them makes a network blip look like a stale library — the exact category error #38 was filed about, one level down.

The remote URL is never printed. A remote rewritten by url.insteadOf expands into a live token; that has leaked a credential on koala before.

The default run's silence is now a test, not a comment. One of the five fixture cases stubs a newer remote tag and asserts the default invocation ignores it, so the "no network I/O" promise in doctor's header is enforced rather than trusted.

Live, on the host that motivated it

$ bin/doctor --online
FAIL behind: this host has 0.12.1; origin has released 0.13.4 —
     run 'task update' and '/plugin update skills@mathias'

$ bin/doctor
skills doctor: clean — 41 skills

Same host, same moment: clean offline, correctly red online. That is the gap this issue described, now visible on demand.

The second observation stands unresolved

Something re-ran install.sh with the default SKILLS_CHECKOUT_DIR at 14:05, which re-pointed every link from ~/dev/skills to ~/.local/share/skills. Still true — the doctor output above names ~/.local/share/skills as the checkout. It is arguably correct behaviour (the default is documented as load-bearing) but it means the canonical checkout can move without anyone asking, and a ~/dev/skills you are actively editing silently stops being what any harness loads. Worth knowing what triggered it before deciding whether that is a feature; not filed separately yet.

Shipped in `b2af4e1` — option 2, the opt-in flag. ```bash task doctor -- --online # or bin/doctor --online ``` One `git ls-remote` against origin. Belongs in a scheduled per-host job, not the SessionStart hook — a check that costs latency on every session start is a check someone eventually disables. ## Design calls, each for a reason **Order, not equality.** A host *ahead* of the newest tag is the normal state between a release commit and its tag landing. Same reasoning as `task check`'s ordering rule (#34), reusing `bin/newer-version`. **An unreachable remote is a WARN naming itself, not a staleness FAIL.** "I could not check" and "you are behind" are different answers, and collapsing them makes a network blip look like a stale library — the exact category error #38 was filed about, one level down. **The remote URL is never printed.** A remote rewritten by `url.insteadOf` expands into a live token; that has leaked a credential on koala before. **The default run's silence is now a test, not a comment.** One of the five fixture cases stubs a newer remote tag and asserts the *default* invocation ignores it, so the "no network I/O" promise in doctor's header is enforced rather than trusted. ## Live, on the host that motivated it ``` $ bin/doctor --online FAIL behind: this host has 0.12.1; origin has released 0.13.4 — run 'task update' and '/plugin update skills@mathias' $ bin/doctor skills doctor: clean — 41 skills ``` Same host, same moment: clean offline, correctly red online. That is the gap this issue described, now visible on demand. ## The second observation stands unresolved Something re-ran `install.sh` with the default `SKILLS_CHECKOUT_DIR` at 14:05, which re-pointed every link from `~/dev/skills` to `~/.local/share/skills`. Still true — the doctor output above names `~/.local/share/skills` as the checkout. It is arguably correct behaviour (the default is documented as load-bearing) but it means the canonical checkout can move without anyone asking, and a `~/dev/skills` you are actively editing silently stops being what any harness loads. Worth knowing what triggered it before deciding whether that is a feature; not filed separately yet.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/skills#38