Skip to content

fix: regenerate the skill changelog preview after the file set changes - #3296

Merged
Patrick-Erichsen merged 1 commit into
openclaw:mainfrom
Yigtwxx:fix/skill-publish-changelog-preview-stale
Jul 30, 2026
Merged

fix: regenerate the skill changelog preview after the file set changes#3296
Patrick-Erichsen merged 1 commit into
openclaw:mainfrom
Yigtwxx:fix/skill-publish-changelog-preview-stale

Conversation

@Yigtwxx

@Yigtwxx Yigtwxx commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where publishers updating an existing skill see a generated
changelog that describes a bundle they are no longer publishing. Changing the
selected files in a way that keeps the file count the same — swapping one
bundled script for another, or replacing a helper file — leaves the previously
generated text in the "What changed" field.

The affected surface is the skill publish form in update mode
(/skills/publish?updateSlug=...), where that field is prefilled from
skills.generateChangelogPreview.

Why This Change Was Made

The form caches its last preview request in changelogKeyRef so ordinary
re-renders do not re-run generation. The key was built from the slug, version,
SKILL.md size and lastModified, and normalizedPaths.length — the path
count. The path list itself is what the form sends to the action as
filePaths, so two different bundles holding the same number of files produce
an identical key and the second request is skipped.

Nothing reset that key when the selection changed, and the generation effect
returns early while the field is non-empty. Together those two things mean that
once a preview has landed, no later change to the file set can replace it for
the rest of the session.

The plugin publish form already covers both halves of this in
src/routes/plugins/publish.tsx: it keys on normalizedPaths.join("\0") and
resets the cached key when the file set changes. The skill form now does the
same, so the two publish forms agree.

Manually written text is never discarded — the reset returns early when
changelogTouchedRef is set, and there is a regression test for that.

Of the two changes, the reset is what restores the behavior; keying on the joined
paths removes the underlying mismatch so the guard no longer depends on the reset
for correctness, and matches the sibling form.

Non-goals, kept out to hold the change to one concern:

  • Sharing this logic between the two publish forms. They are now consistent;
    extracting a common hook is a separate refactor.
  • The preview action's own file-diff behavior.

User Impact

The generated changelog now describes the bundle that is actually about to be
published. Previously a publisher who swapped a file after the first preview
landed would either submit a changelog naming a file that is no longer in the
upload, or have to notice the problem and overwrite the field by hand.

Evidence

Base commit: 79ef4af1. The fix is not present on mainchangelogKeyRef there
is still built from normalizedPaths.length, and the skill form has no effect that
resets it.

Behavior read out of the mounted Upload form. The same SKILL.md instance is
reused across both selections so its size and lastModified do not change; only
a sibling file is swapped, keeping the path count at two:

step before after
select [SKILL.md, scripts/alpha.sh] 1 preview call, field shows - Generated for [SKILL.md, scripts/alpha.sh] same
swap to [SKILL.md, scripts/beta.sh] still 1 preview call, last filePaths ["SKILL.md","scripts/alpha.sh"], field unchanged 2 preview calls, last filePaths ["SKILL.md","scripts/beta.sh"], field shows - Generated for [SKILL.md, scripts/beta.sh]

The new regression test fails on the parent commit and passes with the fix:

$ VITE_CONVEX_URL=https://example.invalid bunx vitest run \
    src/__tests__/skills-publish-route.test.tsx        # parent commit 79ef4af1

 × regenerates the changelog preview when the bundle swaps one file for another
AssertionError: expected "vi.fn()" to be called 2 times, but got 1 times
    1173|     expect(generateChangelogPreview).toHaveBeenNthCalledWith(

 Test Files  1 failed (1)
      Tests  1 failed | 31 passed (32)
$ VITE_CONVEX_URL=https://example.invalid bunx vitest run \
    src/__tests__/skills-publish-route.test.tsx        # with the fix

 Test Files  1 passed (1)
      Tests  32 passed (32)

The second new test (keeps a manually written changelog when the file set changes) passes on both sides — it guards the reset against discarding text the
publisher typed.

Both publish route suites together, to confirm the plugin form is unaffected:

$ bunx vitest run src/__tests__/skills-publish-route.test.tsx \
    src/__tests__/plugins-publish-route.test.tsx
 Test Files  2 passed (2)
      Tests  69 passed (69)

Gates run locally on Windows:

  • bunx tsc --noEmit — clean
  • bun run lint — clean
  • bun run deadcode:ci — clean
  • bun run format:check — the only two files it reports are CLAUDE.md and
    .agents/skills/autoreview/CLAUDE.md; both report identically on an unmodified
    checkout of 79ef4af1, so they are pre-existing and untouched here.
  • bun run ci:unit — 5541 passed. The 24 failures are pre-existing on this
    platform: 79ef4af1 fails the same 14 files with the same 24 tests (5539
    passed there, the difference being the two tests added by this PR). They are the
    scripts/ worker, CLI and security-dataset suites that shell out to bun, plus
    convex/lib/githubAccount.test.ts and src/routes/-management.test.tsx. Linux
    CI is the authoritative signal.

The Vercel preview check will need OpenClaw Foundation team authorization, as with
other fork pull requests.

The publish form keyed its generated-changelog cache on the number of
selected paths rather than the paths themselves, and never reset that key
when the selection changed. Swapping one bundled file for another left the
key untouched, so the form kept showing a changelog generated from the
previous bundle even though the new path list is what gets sent to the
preview action.

The plugin publish form already keys on the joined paths and resets the
cache when the file set changes; the skill form now does both.
@Yigtwxx
Yigtwxx requested a review from a team as a code owner July 29, 2026 19:12
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@Yigtwxx is attempting to deploy a commit to the OpenClaw Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@Patrick-Erichsen
Patrick-Erichsen merged commit 2cd6317 into openclaw:main Jul 30, 2026
30 of 31 checks passed
@Patrick-Erichsen

Copy link
Copy Markdown
Collaborator

Thanks @Yigtwxx — much appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants