Skip to content

Reconcile stale entries when regenerating skills-lock.json - #70

Draft
warp-agent-staging[bot] wants to merge 2 commits into
mainfrom
factory/devx-8492-lock-reconciliation
Draft

Reconcile stale entries when regenerating skills-lock.json#70
warp-agent-staging[bot] wants to merge 2 commits into
mainfrom
factory/devx-8492-lock-reconciliation

Conversation

@warp-agent-staging

@warp-agent-staging warp-agent-staging Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

scripts/update_common_skills_lock regenerated a downstream skills-lock.json additively: it seeded a temp dir from the existing lock and ran skills add, which merges into whatever lock it finds and never removes an entry for a skill that's no longer in the source. A rename or deletion in warpdotdev/common-skills left a ghost entry behind, pointing at a skillPath that no longer exists. Since .github/workflows/update-downstream-skill-locks.yml runs this on every push to main and opens the downstream PRs with squash auto-merge enabled, a corrupted lock could land unreviewed.

Fixes DEVX-8492.

Changes

  • scripts/update_common_skills_lock: regenerates the warpdotdev/common-skills portion of the lock from scratch in a clean, unseeded temp directory (instead of seeding it with the existing lock), then merges in any entries from other sources unmodified. Since nothing is seeded, skills add can only ever emit entries for skills it actually finds in the current source — there is nothing stale for it to merge forward, so the bug's root cause is removed structurally rather than patched after the fact.
  • Fails closed: if regenerating produces zero warpdotdev/common-skills entries while the existing lock has some, the script aborts with a non-zero exit and leaves skills-lock.json completely untouched, instead of writing a lock that dropped every locked skill. See "Revision" below for why this was added.
  • Added scripts/tests/update_common_skills_lock_test.sh, a self-contained regression suite, plus scripts/tests/fake-bin/npx, a fake npx that deterministically models skills add ... --copy from a local fixture directory (no network access). Wired into a new .github/workflows/test-scripts.yml, run on every push to main and every pull request.
  • scripts/README.md: documented the clean-regeneration behavior, the fail-closed guard, and the new test suite.

Revision (addressing review findings)

An adversarial review of the first version of this PR found two issues, both fixed in this revision:

  1. Critical — the original fix failed open. The first version kept seeding the temp dir with the existing lock and pruned an entry only if its skillPath wasn't found copied under the temp dir. If skills add exited 0 without actually copying anything (e.g. a broken CLI run), every warpdotdev/common-skills entry looked "not found" and got pruned — deleting all of them — while the lone different-source entry survived untouched. That result is worse than the bug this PR fixes, and would have auto-merged into warp and warp-server. Fixed by restructuring the regeneration to not seed the temp dir at all (so nothing stale can survive the merge in the first place), plus an explicit fail-closed guard for the case where regeneration produces nothing.
  2. Important — no regression coverage. Added the self-contained shell test suite and CI workflow described above.

Verification

Regression suite (scripts/tests/update_common_skills_lock_test.sh, runs in CI): 5 tests, all passing —

  • rename: stale entry pruned, renamed entry added, siblings and the foreign-source entry untouched
  • plain deletion: stale entry pruned, siblings and the foreign-source entry untouched
  • idempotence: a second run is byte-identical and reports "already up to date"
  • fails closed when the fake npx writes a technically-valid but empty lock (no copies)
  • fails closed when the fake npx produces no candidate lock at all

I confirmed these tests are not vacuous by running them against the original (pre-fix) script and against the first, since-replaced version of this fix — both fail multiple tests in the suite, including (for the first fix) the two fail-closed tests, reproducing the exact regression the review found.

Manual validation, using a local git fixture repo as a stand-in for warpdotdev/common-skills (via a file:// source, so the skills CLI takes the identical clone+copy code path as the real GitHub source) and the fake npx:

  • Rename and plain-deletion scenarios: stale entry pruned, foreign-source entry byte-for-byte untouched, in both cases.
  • Notably, the plain-deletion case is worse than the issue describes on the original script: since nothing else changes, the buggy script reports "already up to date" while silently keeping the ghost entry — no diff ever surfaces it.
  • No-op case: running the fixed script again against an already-current lock reports "already up to date", exits 0, and leaves the file untouched.
  • Fail-closed guard, both sub-cases: a broken npx that writes an empty lock, and one that writes nothing at all — both abort with a non-zero exit and leave the existing lock byte-identical to before.
  • Real downstream locks, no regression: ran the actual fixed script (real warpdotdev/common-skills source, real network) against copies of the real warpdotdev/warp and warpdotdev/warp-server skills-lock.json files. Output was identical to the original (unfixed) script on the same inputs — only computedHash bumps for skills whose content changed upstream since those locks were generated; no entries added or removed.

bash -n passes on all three shell scripts (scripts/update_common_skills_lock, scripts/tests/update_common_skills_lock_test.sh, scripts/tests/fake-bin/npx).

Out of scope

  • Did not add a way to override COMMON_SKILLS_SOURCE for ad hoc/manual testing; the fix itself doesn't need one, and the shipped regression suite covers this via the fake npx instead.
  • A partial-but-nonzero corrupted CLI result (e.g. only some skills copied due to some other CLI bug) isn't independently validated beyond what skills add itself reports — only the zero-materialization case is guarded against, per the review's explicit "at minimum" scope for finding 1.

update_common_skills_lock seeded its temp dir from the existing
downstream lock and ran `skills add`, which merges into whatever lock
it finds but never removes an entry for a skill that no longer exists
in the source. A rename or deletion in warpdotdev/common-skills left a
ghost entry behind pointing at a skillPath that no longer exists.

Reconcile the candidate lock before comparing/copying it back: drop
any entry whose source is warpdotdev/common-skills unless this run's
`--copy` actually materialized its skillPath under the temp directory.
Entries from any other source, including hand-added ones, are left
untouched. This reuses the copy `skills add` already produced instead
of making a second fetch.

Fixes DEVX-8492.

Co-Authored-By: Warp Agent <agent@warp.dev>
@warp-agent-staging warp-agent-staging Bot added the factory:wilson Routes this item to the wilson factory label Aug 13, 2026
@warp-agent-staging

Copy link
Copy Markdown
Contributor Author

This PR was generated with Warp.

View run View conversation

Review of the previous revision found that pruning by checking whether
a copied path existed under the temp dir failed open: if skills add
exited 0 without actually copying anything (e.g. a broken CLI run),
every warpdotdev/common-skills entry looked stale and got deleted,
while the one entry from another source survived. That result is
worse than the original bug and would auto-merge into warp and
warp-server.

Restructure the fix: regenerate the warpdotdev/common-skills portion
of the lock from scratch in a clean, unseeded temp directory instead
of seeding it with the existing lock and pruning what didn't reappear.
skills add can then only ever emit entries for skills it actually
finds, so nothing stale can survive the merge in the first place.
Entries from any other source are carried over from the existing lock
unmodified. As a backstop, fail closed with a non-zero exit and leave
the existing lock untouched if regenerating produces no
warpdotdev/common-skills entries at all while the existing lock has
some - that is a sign the run didn't discover or copy anything, not
that every skill vanished upstream.

Add scripts/tests/update_common_skills_lock_test.sh, a self-contained
regression suite that runs the real script against a fake npx
(scripts/tests/fake-bin/npx) modeling `skills add ... --copy`
deterministically from a local fixture directory, with no network
access. Covers a rename, a plain deletion, foreign-source
preservation, idempotence, and the fail-closed guard. Wire it into a
new CI workflow that runs on push to main and on every pull request.

Co-Authored-By: Warp Agent <agent@warp.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

factory:wilson Routes this item to the wilson factory

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant