Skip to content

Add thv skill upgrade: re-resolve pinned skills to newer content#5896

Open
samuv wants to merge 2 commits into
skills-lock/04-syncfrom
skills-lock/05-upgrade
Open

Add thv skill upgrade: re-resolve pinned skills to newer content#5896
samuv wants to merge 2 commits into
skills-lock/04-syncfrom
skills-lock/05-upgrade

Conversation

@samuv

@samuv samuv commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Why: RFC THV-0080 needs a controlled way to pull newer content for skills pinned by source (a registry name, an OCI tag, a git branch), without silently drifting the lock file on every plain re-install. This ships the full upgrade vertical slice in one PR, matching PR4's precedent (the CLI command can't exist without its API endpoint).
  • What:
    • Upgrade re-resolves each targeted entry's Source — via the same git/OCI/registry dispatch order Install uses (resolveLatestState), stopping short of extraction/DB/lock writes — and installs newer content only when the digest actually changed. Source itself is never rewritten.
    • Entries pinned to an immutable reference (an OCI digest or a full git commit hash — isImmutableSource, added in PR4's pin.go) report not-upgradable: there's nothing newer to resolve to.
    • --preview reports what would change without persisting it (still fetches to compare digests — an OCI pull has no lighter "digest only" primitive, matching the RFC's own "preview is not side-effect-free" note; git sources resolve without touching disk). --allow-ref-change permits the resolved reference itself changing. --fail-on-changes gives CI a freshness gate.
    • var _ skills.SkillLockService = (*service)(nil) lands here now that both Sync (PR4) and Upgrade exist; SkillsRouter widens from PR4's narrow skillSyncer interface to the full skills.SkillLockService.
    • thv skill upgrade [name...] CLI.

Part of the production stack for #5715 (RFC THV-0080). Stack: 5/6 — lockfile → lock-service → install-hooks → sync → upgrade → cli-exitcodes. Based on #5895 (PR4).

Type of change

  • New feature

Test plan

  • Unit tests (task test)
  • E2E tests (task test-e2e, scoped: ginkgo --label-filter=skills-lock)
  • Linting (task lint-fix)

Unit tests cover: up-to-date (source unchanged), installs newer content and preserves Source, preview reports without persisting, not-upgradable for an immutable source, unknown name returns 404, --fail-on-changes stops at the first change. API handler tests including the 501 path and a --fail-on-changes 409 propagation. New E2E spec: build+push v1 → install → republish newer content at the same OCI reference → upgrade --preview reports the change without touching the lock file → upgrade applies it and the lock file records the new digest with Source unchanged.

Does this introduce a user-facing change?

Not yet — same TOOLHIVE_SKILLS_LOCK_ENABLED gate as the rest of the stack. Once the full stack lands: thv skill upgrade re-resolves and updates a project's pinned skills.

Special notes for reviewers

  • resolveLatestState/resolveOCILatest/resolveGitLatest intentionally duplicate a slice of Install's dispatch logic rather than refactoring Install to expose a resolve-only phase — a deeper split felt like more surgery than this PR should carry; flagging for a second opinion on whether that tradeoff is right.
  • The API layer discards partial UpgradeResult outcomes when --fail-on-changes trips (only the error is returned) — a caller doesn't currently see which earlier entries already succeeded before the stop. Noting as a known simplification, not fixed here.

🤖 Generated with Claude Code

@github-actions github-actions Bot added the size/XL Extra large PR: 1000+ lines changed label Jul 21, 2026
@samuv
samuv force-pushed the skills-lock/05-upgrade branch from dd81407 to a7e9269 Compare July 21, 2026 15:31
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 21, 2026
@samuv samuv self-assigned this Jul 21, 2026
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 56.47059% with 74 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (skills-lock/04-sync@e4b12ca). Learn more about missing BASE report.

Files with missing lines Patch % Lines
pkg/skills/skillsvc/upgrade.go 53.73% 51 Missing and 11 partials ⚠️
pkg/skills/client/client.go 0.00% 12 Missing ⚠️
Additional details and impacted files
@@                  Coverage Diff                   @@
##             skills-lock/04-sync    #5896   +/-   ##
======================================================
  Coverage                       ?   71.73%           
======================================================
  Files                          ?      709           
  Lines                          ?    72653           
  Branches                       ?        0           
======================================================
  Hits                           ?    52115           
  Misses                         ?    16767           
  Partials                       ?     3771           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@samuv
samuv force-pushed the skills-lock/04-sync branch from 9c2d5f5 to 06a66f8 Compare July 21, 2026 16:58
@samuv
samuv force-pushed the skills-lock/05-upgrade branch from a7e9269 to 9deff64 Compare July 21, 2026 16:58
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 21, 2026
@samuv
samuv force-pushed the skills-lock/04-sync branch from 06a66f8 to 42a03de Compare July 21, 2026 17:08
@samuv
samuv force-pushed the skills-lock/05-upgrade branch from 9deff64 to 3e750f4 Compare July 21, 2026 17:08
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 21, 2026
@samuv
samuv force-pushed the skills-lock/04-sync branch from 42a03de to 4604083 Compare July 21, 2026 17:14
@samuv
samuv force-pushed the skills-lock/05-upgrade branch from 3e750f4 to cf3c890 Compare July 21, 2026 17:14
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 21, 2026
@samuv
samuv force-pushed the skills-lock/05-upgrade branch from cf3c890 to aecb406 Compare July 21, 2026 17:17
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 21, 2026
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 21, 2026
@samuv
samuv force-pushed the skills-lock/05-upgrade branch from 664f512 to 7aa5c69 Compare July 21, 2026 17:34
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 21, 2026
@samuv

samuv commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Tracked in #5899 (RFC THV-0080 stack).

samuv added 2 commits July 22, 2026 22:08
RFC THV-0080 needs a controlled way to pull newer content for
skills pinned by source, without silently drifting the lock file
on every install. This adds the full upgrade vertical slice:
service logic, HTTP endpoint, client, and CLI command.

- Upgrade re-resolves each targeted entry's Source (via the same
  git/OCI/registry dispatch order Install uses, stopping short of
  extraction — resolveLatestState) and installs newer content when
  the digest changed; Source itself is never rewritten
- Entries pinned to an immutable reference (an OCI digest or full
  git commit hash) report not-upgradable — there's nothing newer to
  resolve to
- --preview reports what would change without persisting it;
  --allow-ref-change permits the resolved reference itself
  changing; --fail-on-changes gives CI a freshness gate
- var _ skills.SkillLockService = (*service)(nil) lands here now
  that both Sync and Upgrade exist; SkillsRouter widens from the
  narrow skillSyncer interface (PR4) to the full interface
- `thv skill upgrade [name...]` CLI

Part of the production stack for #5715 (RFC THV-0080). Stack: 5/6.
Upgrade installed each target in sequence and only checked
FailOnChanges after each one returned, so a multi-skill upgrade
would install the first changed skill for real before reporting the
conflict — a partial mutation a read-only CI gate must never
produce. Split into a resolve-only planning pass (also reused to
avoid re-resolving Source a second time when applying) and an apply
pass that only runs once every target has been checked. Upgrade also
now preserves a skill's existing clients instead of expanding to
every detected client, matching Sync's behavior.
@samuv
samuv force-pushed the skills-lock/04-sync branch from d94ef78 to e4b12ca Compare July 22, 2026 20:13
@samuv
samuv force-pushed the skills-lock/05-upgrade branch from 7aa5c69 to 16a5271 Compare July 22, 2026 20:13
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Extra large PR: 1000+ lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant