Add e2e lifecycle coverage for existing installs#183
Open
markcallen wants to merge 5 commits into
Open
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates install patch behavior for Claude .skill archives so unreadable existing archives can be replaced with canonical packaged skill content instead of failing the install.
Changes:
- Adds Claude skill patch fallback logic in TypeScript and Python installers.
- Adds regression tests for unreadable Claude
.skillarchives in TypeScript and Python. - Documents the recovery behavior in
PRD.md.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
PRD.md |
Adds the unreadable Claude .skill archive recovery requirement and acceptance criterion. |
packages/ballast-typescript/src/install.ts |
Introduces TypeScript fallback handling for Claude skill archive patching. |
packages/ballast-typescript/src/install.test.ts |
Adds TypeScript regression coverage for invalid Claude .skill archive replacement. |
packages/ballast-python/ballast/cli.py |
Adds Python fallback handling for Claude skill archive patching and changes common agent registration. |
packages/ballast-python/tests/test_cli.py |
Adds Python regression coverage for invalid Claude .skill archive replacement. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 26 out of 26 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (3)
cli/ballast/main.go:2282
- For cursor/opencode, this condition allows deletion solely because the target matches, without checking that the stale skill was present in the previous
.rulesrc.jsonor otherwise owned by Ballast. SinceremoveStaleManagedFilesbuilds candidates from every supported skill name, a user-authored.cursor/rules/<supported-skill>.mdcor.opencode/skills/<supported-skill>.mdthat was never managed by Ballast can be removed during refresh, violating the requirement to avoid deleting unrelated user files.
for _, file := range stringDifference(allManagedSkillPaths(root, target), managedSkillPaths(root, target, next.Skills)) {
if !ballastOwnsManagedFile(file) && !trackedPaths[file] && !allowConfigBackedStaleSkillRemoval(target, file) {
continue
cli/ballast/main.go:2730
- Claude
.skillarchives generated by the backends currently contain the raw skillSKILL.mdwithout the newCreated by [Ballast]marker, so this ownership check returns false unless the path also appears in a managed support-file section. If a support file was disabled, skipped, deleted, or preserved as unmanaged, refresh reconciliation will leave stale Claude skill archives behind even though they were Ballast-installed.
if strings.HasSuffix(path, ".skill") {
reader, err := zip.NewReader(bytes.NewReader(content), int64(len(content)))
if err != nil {
return false
}
for _, file := range reader.File {
if file.Name != "SKILL.md" {
continue
}
rc, err := file.Open()
if err != nil {
return false
}
data, readErr := io.ReadAll(rc)
_ = rc.Close()
if readErr != nil {
return false
}
return strings.Contains(string(data), ballastManagedMarker)
cli/ballast/main.go:2273
- Stale rule cleanup cannot remove cursor/opencode agent rules because those targets have no support-file tracking and generated agent rule files do not include the
Created by [Ballast]marker used byballastOwnsManagedFile. As a result, removing a saved agent and refreshing a cursor/opencode install leaves the old managed rule files in place instead of reconciling the retained target.
for _, file := range stringDifference(allManagedRulePaths(root, target), managedRulePaths(root, target, next)) {
if !ballastOwnsManagedFile(file) && !trackedPaths[file] {
continue
Comment on lines
+2348
to
+2350
| for _, file := range stringDifference(allManagedSkillPaths(root, target), managedSkillPaths(root, target, next.Skills)) { | ||
| if !ballastOwnsManagedFile(file) && !trackedPaths[file] && !allowConfigBackedStaleSkillRemoval(target, file) { | ||
| continue |
|
|
||
| PROJECT="${WORKDIR}/doctor-after-lifecycle-change" | ||
| create_monorepo_fixture "${PROJECT}" | ||
| add_typescript_profile "${PROJECT}" |
| script: ./scripts/e2e-add-task-system.sh | ||
| needs_typescript: true | ||
| - name: doctor-after-lifecycle-change-e2e | ||
| script: ./scripts/e2e-doctor-after-lifecycle-change.sh |
|
|
||
| ( | ||
| cd "${PROJECT}" | ||
| ballast install --target codex --agent linting --yes >/dev/null |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
scripts/e2e-*.shcoverage for existing-install lifecycle and upgrade flowstaskSystemand update backend coverage for skill refresh and unreadable Claude archive recoveryTesting
./scripts/run-unit-tests-pre-push.shexcept the final CLIgo teststep neededGOCACHE=/tmp/go-build-clibecause the default cache path was read-only in this environmentenv GOCACHE=/tmp/go-build-cli go test ./...incli/ballastgo test ./...inpackages/ballast-gouv run --python 3.12 python -m unittest tests.test_cliinpackages/ballast-pythonpnpm --filter @everydaydevopsio/ballast run test -- doctor.test.tsfor script in ./scripts/e2e-*.sh; do "$script"; doneFollow-up