Skip to content

fix(api): accept version field in ClawHubInstallRequest (#6038)#6039

Merged
houko merged 2 commits into
librefang:mainfrom
DaBlitzStein:fix/clawhub-install-version
Jun 15, 2026
Merged

fix(api): accept version field in ClawHubInstallRequest (#6038)#6039
houko merged 2 commits into
librefang:mainfrom
DaBlitzStein:fix/clawhub-install-version

Conversation

@DaBlitzStein

Copy link
Copy Markdown
Contributor

Summary

Closes #6038.

Installing any skill from the dashboard's ClawHub / SkillHub browser fails with 422 Unprocessable Entity.
The dashboard's clawhubInstall (dashboard/src/api.ts) posts { slug, version, hand }, but ClawHubInstallRequest was declared #[serde(deny_unknown_fields)] with only slug and hand — no version — so the axum Json extractor rejected every request before the handler ran ("unknown field version").

The one shared ClawHubInstallRequest type backs three install handlers, so the single missing field broke all of them:

  • POST /api/clawhub/install (routes/skills/clawhub.rs::clawhub_install)
  • POST /api/clawhub-cn/install (routes/skills/clawhub.rs::clawhub_cn_install — China mirror)
  • POST /api/skillhub/install (routes/skills/skillhub.rs::skillhub_install)

Change

  • Add version: Option<String> with #[serde(default)] to ClawHubInstallRequest (crates/librefang-api/src/types.rs).
    The installer still resolves to the latest published version — the field is accepted to keep the request well-formed under deny_unknown_fields, not (yet) to drive version selection. slug-only bodies keep working.
  • Regenerated openapi.json (the type is a utoipa::ToSchema); the pre-commit hook auto-synced xtask/baselines/openapi.sha256.

Verification

  • cargo check -p librefang-api — clean.
  • cargo clippy -p librefang-api --all-targets -- -D warnings — clean.
  • cargo test -p librefang-api --lib clawhub_install_request — 2/2 pass:
    • clawhub_install_request_accepts_dashboard_body_with_version — the exact dashboard body {"slug","version","hand"} now deserializes.
    • clawhub_install_request_slug_only_still_works — backward-compatible slug-only body.
  • cargo xtask codegen --openapi — regenerated spec; ClawHubInstallRequest.properties now lists slug, version, hand.

Out-of-scope follow-ups

None. The handler ignoring version (always installing latest) is intentional and documented on the field; wiring real version selection is a separate feature, not a regression.

@github-actions github-actions Bot added size/S 10-49 lines changed area/docs Documentation and guides has-conflicts PR has merge conflicts that need resolution labels Jun 9, 2026
@DaBlitzStein
DaBlitzStein force-pushed the fix/clawhub-install-version branch from 51863db to 36235bc Compare June 9, 2026 16:28
@github-actions github-actions Bot added ready-for-review PR is ready for maintainer review has-conflicts PR has merge conflicts that need resolution and removed has-conflicts PR has merge conflicts that need resolution ready-for-review PR is ready for maintainer review labels Jun 9, 2026
…6038)

The dashboard's clawhubInstall posts {slug, version, hand}, but
ClawHubInstallRequest used #[serde(deny_unknown_fields)] without a
version field, so the axum Json extractor rejected every ClawHub /
clawhub-cn / skillhub install with 422 ("unknown field `version`").

Add version: Option<String> (#[serde(default)]); the installer still
resolves to the latest published version, so the field is accepted to
keep the request well-formed rather than driving version selection yet.
The one shared type backs all three install endpoints, so this repairs
POST /api/clawhub/install, /api/clawhub-cn/install and /api/skillhub/install.

Regenerated openapi.json. Tests: clawhub_install_request_accepts_dashboard_body_with_version, clawhub_install_request_slug_only_still_works.
@DaBlitzStein
DaBlitzStein force-pushed the fix/clawhub-install-version branch from 36235bc to 5dd2745 Compare June 11, 2026 17:24
@houko

houko commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Re-reviewed after the latest push — this is a correct, well-scoped fix for the 422 and the two regression tests (accepts_dashboard_body_with_version / slug_only_still_works) plus the regenerated openapi.json cover both shapes. Good.

One thing worth a tracked follow-up (not blocking this PR): the field is accepted but silently ignored — the installer always resolves to latest, so a client that requests a specific version gets latest with no signal. Today the dashboard only ever sends "latest", so there's no user-visible impact, but once a non-latest value can be sent this becomes a silent wrong-result. Suggest either wiring version through to the resolver in the follow-up, or, until then, a warn!/debug! when version is Some(v) and v != "latest" so it's observable rather than silently dropped. The doc-comment already flags the intent ("rather than driving version selection yet"), so a one-line issue to honor it later would close the loop.

@houko houko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding during daily review pass:

Doc-comment mid-sentence line wrap in crates/librefang-api/src/types.rs

The doc comment for the version field wraps mid-sentence at ~80 chars:

/// Requested version (e.g., "latest"). The dashboard always sends this;
/// the installer currently resolves to the latest published version, so
/// the field is accepted to keep the request well-formed under
/// `deny_unknown_fields` rather than driving version selection yet.

CLAUDE.md (Prose wrapping section): "The only legitimate line break inside a paragraph is at a complete sentence boundary. This rule applies universally: … Source code doc-comments."

Fix — one sentence per line:

/// Requested version (e.g., "latest"). The dashboard always sends this; the installer currently resolves to the latest published version, so the field is accepted to keep the request well-formed under `deny_unknown_fields` rather than driving version selection yet.

After updating the Rust source, regenerate openapi.json (pre-commit hook / cargo xtask codegen openapi) to update the description string and xtask/baselines/openapi.sha256.

No other issues found; the serde fix and both regression tests look correct.


Generated by Claude Code

@github-actions github-actions Bot added has-conflicts PR has merge conflicts that need resolution and removed ready-for-review PR is ready for maintainer review labels Jun 14, 2026
# Conflicts:
#	xtask/baselines/openapi.sha256
@github-actions github-actions Bot added ready-for-review PR is ready for maintainer review and removed has-conflicts PR has merge conflicts that need resolution labels Jun 15, 2026
@houko
houko merged commit 0f9789c into librefang:main Jun 15, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation and guides ready-for-review PR is ready for maintainer review size/S 10-49 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ClawHub skill install always fails with 422: dashboard sends version but ClawHubInstallRequest denies unknown fields

2 participants