Compare commits

...

4 Commits

Author SHA1 Message Date
Patrick Honkonen
86300942de Apply suggestions from code review
Co-authored-by: Álison Fernandes <vvolkgang@users.noreply.github.com>
2026-03-16 12:46:48 -04:00
Patrick Honkonen
b31c448d25 Fix skill preprocessing: remove $() substitution and add allowed-tools
- Replace $(git branch --show-current) with hardcoded sdlc/sdk-update
  branch name to avoid $() command substitution blocked by permission checks
- Add allowed-tools frontmatter for git and gh commands used in
  preprocessed context
2026-03-16 08:33:30 -04:00
Patrick Honkonen
90b88067ba Add preprocessed context injection to resolving-sdk-updates skill 2026-03-12 15:22:50 -04:00
Patrick Honkonen
97bc0d29e9 llm: Add resolving-sdk-updates skill
Teaches Claude to diagnose and resolve build failures from Bitwarden SDK
(com.bitwarden:sdk-android) version updates with a five-phase workflow:
identify, diagnose, investigate, fix, and assess behavioral impact.
2026-03-12 14:58:16 -04:00
2 changed files with 407 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
---
name: resolving-sdk-updates
description: >
Diagnose and resolve build failures from Bitwarden SDK updates (com.bitwarden:sdk-android).
Investigates sdk-internal PRs, fixes exhaustive when expressions, and assesses behavioral
impact. Use when reviewing SDK update PRs, fixing SDK build errors, encountering "when
expression must be exhaustive" after SDK bump, updating sdk-android in libs.versions.toml,
or when any PR from the sdlc/sdk-update branch has failing CI. Triggered by "fix the SDK
update", "resolve SDK breaking changes", "check the SDK PR", "SDK version bump",
"sdk-android", "sdk-internal". Do NOT use for general dependency updates unrelated to the
Bitwarden SDK.
allowed-tools: Bash(git branch --show-current), Bash(git diff *), Bash(gh run list *), Bash(gh run view *), Bash(gh pr view *), Bash(gh pr diff *)
---
# Resolving SDK Updates
Sequential five-phase workflow for diagnosing and resolving build failures caused by Bitwarden SDK (`com.bitwarden:sdk-android`) version updates.
## Important
- **SDK repo**: `bitwarden/sdk-internal`
- **Artifact**: `com.bitwarden:sdk-android` published to GitHub Packages
- **Version catalog**: `gradle/libs.versions.toml` (key: `sdk-android`)
- **Update branch convention**: `sdlc/sdk-update`
CRITICAL: Before applying any fix, always read the `sdk-internal` PR diff to understand the author's intent. A compile fix alone may be insufficient if the SDK change introduces new behavior that requires a dedicated code path.
## Current State (preprocessed)
- **Current branch**: !`git branch --show-current`
- **SDK version diff vs main**: !`git diff main -- gradle/libs.versions.toml | grep sdk-android || echo "No SDK version change detected"`
- **Latest CI failure (sdlc/sdk-update)**: !`gh run list --branch sdlc/sdk-update --status failure --limit 1 --json databaseId,event,conclusion -q '.[0]' 2>/dev/null`
## Proactive Behavior
- If the preprocessed state above shows CI failures, skip Phase 1 and jump directly to Phase 2.
- If no CI failures exist, focus on Phase 1 (changelog review) and Phase 5 (impact assessment).
- If the SDK version diff above shows no change, confirm the branch and version catalog before proceeding.
---
## Phase 1: Identify the Update
Determine what changed in the SDK version bump. The preprocessed SDK version diff above may already provide this; verify and continue.
1. **Extract version diff** (if not already shown above) from `gradle/libs.versions.toml`:
```bash
git diff main -- gradle/libs.versions.toml | grep sdk-android
```
2. **Parse PR body** for linked `sdk-internal` PRs and Jira tickets:
- SDK PR pattern: `bitwarden/sdk-internal#NNN` or `#NNN` in context of SDK references
- Jira ticket pattern: `PM-NNNNN`
- If working from a GitHub PR: `gh pr view {PR_NUMBER} --json body -q .body`
3. **Record findings**: List each `sdk-internal` PR number and Jira ticket for subsequent phases.
---
## Phase 2: Diagnose Build Failures
Identify and categorize all compiler errors introduced by the SDK change.
1. **Extract CI errors** (if CI is failing):
```bash
gh run list --branch {BRANCH} --status failure --limit 1 --json databaseId -q '.[0].databaseId'
gh run view {RUN_ID} --log-failed | grep -E "e: |error:" | head -50
```
2. **Or build locally**:
```bash
./gradlew app:compileStandardDebugKotlin 2>&1 | grep -E "e: " | head -30
```
3. **Categorize each error** — see `references/common-fix-patterns.md` for the full error category table and fix strategies.
---
## Phase 3: Investigate SDK Changes
Understand the SDK author's intent behind each change. This determines whether a compile fix alone is sufficient or a new code path is needed.
1. **For each referenced `sdk-internal` PR**, retrieve details:
```bash
gh pr view {N} --repo bitwarden/sdk-internal --json title,body,files
```
2. **Read the diff** for breaking changes:
```bash
gh pr diff {N} --repo bitwarden/sdk-internal
```
3. **Focus on**:
- New sealed class variants (will cause exhaustive `when` breaks)
- Changed function signatures (new/removed/renamed parameters)
- New error types in Result sealed classes
- Behavioral changes described in PR body or commit messages
- Deprecation notices or migration guidance
4. **Document** each change with: what changed, why it changed (from PR description), and expected Android impact.
---
## Phase 4: Apply Fixes
Resolve each compiler error using patterns from `references/common-fix-patterns.md`.
1. **Fix each error** according to its category. For exhaustive `when` expressions, the most common fix:
```kotlin
is NewSealedVariant -> {
// Handle new case appropriately based on SDK PR context
}
```
2. **Search for non-exhaustive usages** the compiler won't catch (`when` used as statement not expression, or `when` without `else` on non-sealed types):
```bash
grep -r "AffectedTypeName\." --include="*.kt" app/src/main/kotlin/
grep -r "is AffectedTypeName" --include="*.kt" app/src/main/kotlin/
```
3. **Verify the fix compiles**:
```bash
./gradlew app:compileStandardDebugKotlin
```
4. **Run affected tests** to ensure no regressions:
```bash
./gradlew app:testStandardDebugUnitTest --tests "*.AffectedClassTest"
```
---
## Phase 5: Assess Behavioral Impact
Classify each SDK change and determine if follow-up work is needed beyond compile fixes.
1. **For each change, classify**:
- **Compile-only fix**: New variant added but no feature work needed (e.g., new error type that maps to existing generic error handling)
- **Feature-requiring**: New capability exposed by SDK that needs a new code path, UI, or business logic
2. **For feature-requiring changes**, trace Jira tickets.
First, determine if the `bitwarden-atlassian-tools` MCP plugin is available by checking whether any tools starting with `mcp__plugin_bitwarden-atlassian-tools_` are listed in your available tools.
**If the plugin IS available:**
- Search for existing Android tickets: `project = PM AND text ~ "{keyword}" AND text ~ "Android"`
- Check linked issues from SDK tickets: `issue in linkedIssues(PM-XXXXX)`
- Document: ticket ID, status, assignee, whether Android work is already planned
**If the plugin is NOT available:**
- Inform the user: "Jira ticket tracing requires the `bitwarden-atlassian-tools@bitwarden-marketplace` plugin (github.com/bitwarden/ai-plugins). I can skip ticket tracing or pause for plugin installation."
- Document the Jira ticket IDs (from Phase 1) that should be investigated manually
- Note: behavioral impact assessment will be incomplete without ticket tracing
3. **Produce summary**:
- What was fixed (files changed, error types resolved)
- What needs separate feature work (with Jira ticket references)
- Any risks or behavioral changes to call out in PR review
---
## Examples
### Example 1: SDK update PR with failing CI
User says: "Fix the build errors on PR #6615"
Actions:
1. Extract CI errors from failing run — identify exhaustive `when` breaks
2. Parse PR body for `sdk-internal` PR references
3. Read `sdk-internal` PR diff to understand new sealed variants
4. Add new branches to affected `when` expressions
5. Grep for other usages of affected types across codebase
6. Verify fix compiles and tests pass
Result: Two files fixed with new `when` branches, behavioral impact documented showing compile-only changes.
### Example 2: SDK update PR review (no failures)
User says: "Review the SDK changes in this PR"
Actions:
1. Parse PR body for changelog and `sdk-internal` PR numbers
2. Read each `sdk-internal` PR diff to understand changes
3. Classify each change as compile-only vs feature-requiring
4. Search Jira for tracking tickets on feature-requiring changes
Result: Summary of SDK changes with impact assessment and Jira ticket status.
---
## Performance Notes
- Take your time to thoroughly investigate each `sdk-internal` PR diff before applying fixes.
- Quality is more important than speed — a hasty compile fix that misses behavioral intent creates harder bugs later.
- Do not skip the codebase-wide grep in Phase 4 step 2. The compiler only catches exhaustive `when` expressions, not `when` statements.
---
## Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| 401 Unauthorized fetching SDK | Missing or expired GitHub token | Check `GITHUB_TOKEN` in `user.properties` or env; needs `read:packages` scope |
| Cannot find `sdk-internal` repo | GitHub CLI lacks access | Run `gh auth status` and verify org access; may need `gh auth refresh` |
| `sdk-internal` PR not found | PR number parsed incorrectly | Verify PR number from the update PR body; check `bitwarden/sdk-internal` directly |
| Build succeeds but tests fail | Behavioral change in SDK | Review SDK PR description for behavioral changes; may need test updates |
**Cross-references**:
- `build-test-verify` skill — build and test commands
- `reviewing-changes` skill — general dependency update review checklists
- `implementing-android-code` skill — patterns for new code paths

View File

@@ -0,0 +1,195 @@
# Common Fix Patterns for SDK Updates
Quick-reference for resolving build failures after `com.bitwarden:sdk-android` version bumps.
---
## Error Categories and Fix Strategies
### 1. Exhaustive `when` Expression
**Compiler message**: `'when' expression must be exhaustive, add necessary 'X' branch or 'else' branch instead`
**Fix strategy**:
1. Identify the sealed class/enum that gained a new variant from the SDK diff
2. Search for ALL `when` usages of that type across the codebase:
```bash
grep -rn "is ${TypeName}\." --include="*.kt" app/src/main/kotlin/
grep -rn "when.*${TypeName}" --include="*.kt" app/src/main/kotlin/
```
3. Add the new branch to each `when` expression
4. Determine handling from SDK PR context — does the new variant map to existing behavior or need new logic?
**Template**:
```kotlin
// Before (compiler error)
when (value) {
is SealedType.VariantA -> handleA()
is SealedType.VariantB -> handleB()
}
// After (new variant added)
when (value) {
is SealedType.VariantA -> handleA()
is SealedType.VariantB -> handleB()
is SealedType.VariantC -> handleC() // Added in SDK vX.Y.Z
}
```
---
### 2. Removed API
**Compiler message**: `Unresolved reference: '<functionOrPropertyName>'`
**Fix strategy**:
1. Check SDK diff for what replaced the removed API:
```bash
gh pr diff <N> --repo bitwarden/sdk-internal | grep -A5 -B5 "<removedName>"
```
2. Look for deprecation annotations in previous SDK version
3. Update call sites to use the replacement API
**Template**:
```kotlin
// Before (removed API)
sdkClient.oldMethodName(params)
// After (replacement from SDK changelog)
sdkClient.newMethodName(updatedParams)
```
---
### 3. Renamed Type
**Compiler message**: `Unresolved reference: '<TypeName>'`
**Fix strategy**:
1. Search SDK diff for the old type name to find the rename:
```bash
gh pr diff <N> --repo bitwarden/sdk-internal | grep "<OldTypeName>"
```
2. Update all imports and usages:
```bash
grep -rn "import.*<OldTypeName>" --include="*.kt" app/src/main/kotlin/
grep -rn "<OldTypeName>" --include="*.kt" app/src/main/kotlin/
```
3. Use find-and-replace across affected files
---
### 4. New Required Parameter
**Compiler message**: `No value passed for parameter '<paramName>'`
**Fix strategy**:
1. Check SDK diff for parameter semantics and default behavior:
```bash
gh pr diff <N> --repo bitwarden/sdk-internal | grep -A10 "fun.*<functionName>"
```
2. Determine appropriate value from SDK PR description
3. If parameter has a logical default for Android, use it; otherwise surface to user
**Template**:
```kotlin
// Before (missing parameter)
sdkClient.initializeCrypto(
method = method,
)
// After (new required parameter added)
sdkClient.initializeCrypto(
method = method,
newParam = appropriateValue, // Added in SDK vX.Y.Z — see PM-XXXXX
)
```
---
### 5. New Error Type
**Compiler message**: `'when' expression must be exhaustive` on Result/Error sealed class
**Fix strategy**:
1. Identify the new error variant from SDK diff
2. Determine if it maps to an existing error handling path or needs new UX
3. Search for all catch/when sites handling the parent error type:
```bash
grep -rn "is.*Error\." --include="*.kt" app/src/main/kotlin/
```
4. Add handling — often maps to existing generic error display
**Template**:
```kotlin
// Error handling with new variant
when (error) {
is SdkError.Network -> showNetworkError()
is SdkError.Auth -> showAuthError()
is SdkError.NewErrorType -> {
// Map to appropriate existing handler or add new handling
showGenericError(error.message)
}
}
```
---
## Useful Commands Reference
### CI Error Extraction
```bash
# Get failing run ID for a branch
gh run list --branch <branch> --status failure --limit 1 --json databaseId -q '.[0].databaseId'
# Extract compiler errors
gh run view <run-id> --log-failed | grep -E "e: |error:" | head -50
```
### SDK Diff Investigation
```bash
# View sdk-internal PR details
gh pr view <N> --repo bitwarden/sdk-internal --json title,body,files
# Read full diff
gh pr diff <N> --repo bitwarden/sdk-internal
# Search for specific changes in diff
gh pr diff <N> --repo bitwarden/sdk-internal | grep -B5 -A10 "<searchTerm>"
```
### Codebase Impact Search
```bash
# Find all usages of a type
grep -rn "<TypeName>" --include="*.kt" app/src/main/kotlin/
# Find all when expressions over a sealed type
grep -rn "is <TypeName>\." --include="*.kt" app/src/main/kotlin/
# Find imports of SDK types
grep -rn "import com.bitwarden.sdk.*<TypeName>" --include="*.kt" app/src/main/kotlin/
```
### Jira Ticket Search (via bitwarden-atlassian-tools MCP)
```
# Search for Android tickets related to an SDK change
project = PM AND text ~ "<keyword>" AND text ~ "Android"
# Find linked issues from an SDK ticket
issue in linkedIssues(PM-XXXXX)
# Check ticket status
project = PM AND key = PM-XXXXX
```
### Build Verification
```bash
# Compile check (fastest feedback)
./gradlew app:compileStandardDebugKotlin
# Run specific test class
./gradlew app:testStandardDebugUnitTest --tests "*.AffectedClassTest"
# Full test suite
./gradlew app:testStandardDebugUnitTest
```