mirror of
https://github.com/bitwarden/android.git
synced 2026-05-04 22:49:45 -05:00
Optimize reviewing-changes skill (#6099)
Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
This commit is contained in:
164
.claude/skills/reviewing-changes/checklists/bug-fix.md
Normal file
164
.claude/skills/reviewing-changes/checklists/bug-fix.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Bug Fix Review Checklist
|
||||
|
||||
## Multi-Pass Strategy
|
||||
|
||||
### First Pass: Understand the Bug
|
||||
|
||||
<thinking>
|
||||
Before evaluating the fix:
|
||||
1. What was the original bug/broken behavior?
|
||||
2. What is the expected correct behavior?
|
||||
3. What was the root cause?
|
||||
4. How was the bug discovered? (user report, test, production)
|
||||
5. What's the severity? (crash, data loss, UI glitch, minor annoyance)
|
||||
</thinking>
|
||||
|
||||
**1. Understand root cause:**
|
||||
- What was the broken behavior?
|
||||
- What caused it?
|
||||
- How does this fix address the root cause?
|
||||
|
||||
**2. Assess scope:**
|
||||
- How many files changed?
|
||||
- Is this a targeted fix or broader refactoring?
|
||||
- Does this affect multiple features?
|
||||
|
||||
**3. Check for side effects:**
|
||||
- Could this break other features?
|
||||
- Are there edge cases not considered?
|
||||
|
||||
### Second Pass: Verify the Fix
|
||||
|
||||
<thinking>
|
||||
Evaluate the fix systematically:
|
||||
1. Does this fix address the root cause or just symptoms?
|
||||
2. Are there edge cases not covered?
|
||||
3. Could this break other functionality?
|
||||
4. Is the fix localized or does it ripple through the codebase?
|
||||
5. How do we prevent this bug from returning?
|
||||
</thinking>
|
||||
|
||||
**4. Code changes:**
|
||||
- Does the fix make sense?
|
||||
- Is it the simplest solution?
|
||||
- Any unnecessary changes included?
|
||||
|
||||
**5. Testing:**
|
||||
- Is there a regression test?
|
||||
- Does test verify the bug is fixed?
|
||||
- Are edge cases covered?
|
||||
|
||||
**6. Related code:**
|
||||
- Same pattern in other places that might have same bug?
|
||||
- Should other similar code be fixed too?
|
||||
|
||||
## What to CHECK
|
||||
|
||||
✅ **Root Cause Analysis**
|
||||
- Does the fix address the root cause or just symptoms?
|
||||
- Is the explanation in PR/commit clear?
|
||||
|
||||
✅ **Regression Testing**
|
||||
- Is there a new test that would fail without this fix?
|
||||
- Does test cover the reported bug scenario?
|
||||
- Are related edge cases tested?
|
||||
|
||||
✅ **Side Effects**
|
||||
- Could this break existing functionality?
|
||||
- Are there similar code paths that need checking?
|
||||
- Does this change behavior in unexpected ways?
|
||||
|
||||
✅ **Fix Scope**
|
||||
- Is the fix appropriately scoped (not too broad, not too narrow)?
|
||||
- Are all instances of the bug fixed?
|
||||
- Any related bugs discovered during investigation?
|
||||
|
||||
## What to SKIP
|
||||
|
||||
❌ **Full Architecture Review** - Unless fix reveals architectural problems
|
||||
❌ **Comprehensive Testing Review** - Focus on regression tests, not entire test suite
|
||||
❌ **Major Refactoring Suggestions** - Unless directly related to preventing similar bugs
|
||||
|
||||
## Red Flags
|
||||
|
||||
🚩 **No test for the bug** - How will we prevent regression?
|
||||
🚩 **Fix doesn't match root cause** - Is this fixing symptoms?
|
||||
🚩 **Broad changes beyond the bug** - Should this be split into separate PRs?
|
||||
🚩 **Similar patterns elsewhere** - Should those be fixed too?
|
||||
|
||||
## Key Questions to Ask
|
||||
|
||||
Use `reference/review-psychology.md` for phrasing:
|
||||
|
||||
- "Can we add a test that would fail without this fix?"
|
||||
- "I see this pattern in [other file] - does it have the same issue?"
|
||||
- "Is this fixing the root cause or masking the symptom?"
|
||||
- "Could this change affect [related feature]?"
|
||||
|
||||
## Prioritizing Findings
|
||||
|
||||
Use `reference/priority-framework.md` to classify findings as Critical/Important/Suggested/Optional.
|
||||
|
||||
## Output Format
|
||||
|
||||
Follow the format guidance from `SKILL.md` Step 5 (concise summary with critical issues only, detailed inline comments with `<details>` tags).
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE / REQUEST CHANGES
|
||||
|
||||
**Critical Issues** (if any):
|
||||
- [One-line summary of each critical blocking issue with file:line reference]
|
||||
|
||||
See inline comments for all issue details.
|
||||
```
|
||||
|
||||
## Example Review
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE
|
||||
|
||||
See inline comments for suggested improvements.
|
||||
```
|
||||
|
||||
**Inline comment examples:**
|
||||
|
||||
```
|
||||
**data/auth/BiometricRepository.kt:120** - SUGGESTED: Extract null handling
|
||||
|
||||
<details>
|
||||
<summary>Details</summary>
|
||||
|
||||
Root cause analysis: BiometricPrompt result was nullable but code assumed non-null, causing crash on cancellation (PM-12345).
|
||||
|
||||
Consider extracting null handling pattern:
|
||||
|
||||
\```kotlin
|
||||
private fun handleBiometricResult(result: BiometricPrompt.AuthenticationResult?): AuthResult {
|
||||
return result?.let { AuthResult.Success(it) } ?: AuthResult.Cancelled
|
||||
}
|
||||
\```
|
||||
|
||||
This pattern could be reused if we add other biometric auth points.
|
||||
</details>
|
||||
```
|
||||
|
||||
```
|
||||
**app/auth/BiometricViewModel.kt:89** - SUGGESTED: Add regression test
|
||||
|
||||
<details>
|
||||
<summary>Details</summary>
|
||||
|
||||
Add test for cancellation scenario to prevent regression:
|
||||
|
||||
\```kotlin
|
||||
@Test
|
||||
fun `when biometric cancelled then returns cancelled state`() = runTest {
|
||||
coEvery { repository.authenticate() } returns Result.failure(CancelledException())
|
||||
viewModel.onBiometricAuth()
|
||||
assertEquals(AuthState.Cancelled, viewModel.state.value)
|
||||
}
|
||||
\```
|
||||
|
||||
This prevents regression of the bug just fixed.
|
||||
</details>
|
||||
```
|
||||
166
.claude/skills/reviewing-changes/checklists/dependency-update.md
Normal file
166
.claude/skills/reviewing-changes/checklists/dependency-update.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Dependency Update Review Checklist
|
||||
|
||||
## Multi-Pass Strategy
|
||||
|
||||
### First Pass: Identify and Assess
|
||||
|
||||
<thinking>
|
||||
Before diving into details:
|
||||
1. Which dependencies were updated?
|
||||
2. What are the version changes? (patch, minor, major)
|
||||
3. Are any security-sensitive libraries involved? (crypto, auth, networking)
|
||||
4. Any pre-release versions (alpha, beta, RC)?
|
||||
5. What's the blast radius if something breaks?
|
||||
</thinking>
|
||||
|
||||
**1. Identify the change:**
|
||||
- Which library? Old version → New version?
|
||||
- Major (X.0.0), Minor (0.X.0), or Patch (0.0.X) version change?
|
||||
- Single dependency or multiple?
|
||||
|
||||
**2. Check compilation safety:**
|
||||
- Any imports in codebase that might break?
|
||||
- Any deprecated APIs we're currently using?
|
||||
- Check if this is a breaking change version
|
||||
|
||||
### Second Pass: Deep Analysis
|
||||
|
||||
<thinking>
|
||||
For each dependency update:
|
||||
1. What changes are in this release?
|
||||
2. Are there breaking changes?
|
||||
3. Are there security fixes?
|
||||
4. Do we use the affected APIs?
|
||||
5. How does this affect our codebase?
|
||||
</thinking>
|
||||
|
||||
**3. Review release notes** (if available):
|
||||
- Breaking changes mentioned?
|
||||
- Security fixes included?
|
||||
- New features we should know about?
|
||||
- Deprecations that affect our usage?
|
||||
|
||||
**4. Verify consistency:**
|
||||
- If updating androidx library, are related libraries updated consistently?
|
||||
- BOM (Bill of Materials) consistency if applicable?
|
||||
- Test dependencies updated alongside main dependencies?
|
||||
|
||||
## What to CHECK
|
||||
|
||||
✅ **Compilation Safety**
|
||||
- Look for API deprecations in our codebase
|
||||
- Check if import statements still valid
|
||||
- Major version bumps require extra scrutiny
|
||||
- Beta/alpha versions need stability assessment
|
||||
|
||||
✅ **Security Implications** (if applicable)
|
||||
- Security-related libraries (crypto, auth, networking)?
|
||||
- Check for CVEs addressed in release notes
|
||||
- Review security advisories for this library
|
||||
|
||||
✅ **Testing Implications**
|
||||
- Does this affect test utilities?
|
||||
- Are there breaking changes in test APIs?
|
||||
- Do existing tests still cover the same scenarios?
|
||||
|
||||
✅ **Changelog Review**
|
||||
- Read release notes for breaking changes
|
||||
- Note any behavioral changes
|
||||
- Check migration guides if major version
|
||||
|
||||
## What to SKIP
|
||||
|
||||
❌ **Full Architecture Review** - No code changed, patterns unchanged
|
||||
❌ **Code Style Review** - No code to review
|
||||
❌ **New Test Requirements** - Unless API changed significantly
|
||||
❌ **Security Deep-Dive** - Unless crypto/auth/networking library
|
||||
❌ **Performance Analysis** - Unless release notes mention performance changes
|
||||
|
||||
## Red Flags (Escalate to Full Review)
|
||||
|
||||
🚩 **Major version bump** (e.g., 1.x → 2.0) - Read `checklists/feature-addition.md`
|
||||
🚩 **Security/crypto library** - Read `reference/architectural-patterns.md` and `docs/ARCHITECTURE.md#security`
|
||||
🚩 **Breaking changes in release notes** - Read relevant code sections carefully
|
||||
🚩 **Multiple dependency updates at once** - Check for interaction risks
|
||||
🚩 **Beta/Alpha versions** - Assess stability concerns and rollback plan
|
||||
|
||||
If any red flags present, escalate to more comprehensive review using appropriate checklist.
|
||||
|
||||
## Prioritizing Findings
|
||||
|
||||
Use `reference/priority-framework.md` to classify findings as Critical/Important/Suggested/Optional.
|
||||
|
||||
## Output Format
|
||||
|
||||
Follow the format guidance from `SKILL.md` Step 5 (concise summary with critical issues only, detailed inline comments with `<details>` tags).
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE / REQUEST CHANGES
|
||||
|
||||
**Critical Issues** (if any):
|
||||
- [One-line summary of each critical blocking issue with file:line reference]
|
||||
|
||||
See inline comments for all issue details.
|
||||
```
|
||||
|
||||
## Example Reviews
|
||||
|
||||
### Example 1: Simple Patch Version (No Critical Issues)
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE
|
||||
|
||||
See inline comments for all issue details.
|
||||
```
|
||||
|
||||
**Inline comment example:**
|
||||
```
|
||||
**libs.versions.toml:45** - SUGGESTED: Beta version in production
|
||||
|
||||
<details>
|
||||
<summary>Details</summary>
|
||||
|
||||
androidx.credentials updated from 1.5.0 to 1.6.0-beta03
|
||||
|
||||
Monitor for stability issues - beta releases may have unexpected behavior in production.
|
||||
|
||||
Changelog: Adds support for additional credential types, internal bug fixes.
|
||||
</details>
|
||||
```
|
||||
|
||||
### Example 2: Major Version with Breaking Changes (With Critical Issues)
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** REQUEST CHANGES
|
||||
|
||||
**Critical Issues:**
|
||||
- Breaking API changes in Retrofit 3.0.0 (network/api/BitwardenApiService.kt)
|
||||
- Breaking API changes in Retrofit 3.0.0 (network/api/VaultApiService.kt)
|
||||
|
||||
See inline comments for migration details.
|
||||
```
|
||||
|
||||
**Inline comment example:**
|
||||
```
|
||||
**network/api/BitwardenApiService.kt:15** - CRITICAL: Breaking API changes
|
||||
|
||||
<details>
|
||||
<summary>Details and fix</summary>
|
||||
|
||||
Retrofit 3.0.0 removes `Call<T>` return type. Migration required:
|
||||
|
||||
\```kotlin
|
||||
// Before
|
||||
fun getUser(): Call<UserResponse>
|
||||
|
||||
// After
|
||||
suspend fun getUser(): Response<UserResponse>
|
||||
\```
|
||||
|
||||
Update all API service interfaces to use suspend functions, update call sites to use coroutines instead of enqueue/execute, and update tests accordingly.
|
||||
|
||||
Consider creating a separate PR for this migration due to scope.
|
||||
|
||||
Reference: https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-300
|
||||
</details>
|
||||
```
|
||||
380
.claude/skills/reviewing-changes/checklists/feature-addition.md
Normal file
380
.claude/skills/reviewing-changes/checklists/feature-addition.md
Normal file
@@ -0,0 +1,380 @@
|
||||
# Feature Addition Review Checklist
|
||||
|
||||
## Multi-Pass Strategy
|
||||
|
||||
### First Pass: High-Level Assessment
|
||||
|
||||
<thinking>
|
||||
Before diving into details:
|
||||
1. What is this feature supposed to do?
|
||||
2. How does it fit into the existing architecture?
|
||||
3. What are the security implications?
|
||||
4. What's the scope? (files touched, modules affected)
|
||||
5. What are the highest-risk areas?
|
||||
</thinking>
|
||||
|
||||
**1. Understand the feature:**
|
||||
- Read PR description - what problem does this solve?
|
||||
- Identify user-facing changes vs internal changes
|
||||
- Note any security implications (auth, encryption, data handling)
|
||||
|
||||
**2. Scan file structure:**
|
||||
- Which modules affected? (app, data, network, ui, core?)
|
||||
- Are files organized correctly per module structure?
|
||||
- Any new public APIs introduced?
|
||||
|
||||
**3. Initial risk assessment:**
|
||||
- Does this touch sensitive data or security-critical paths?
|
||||
- Does this affect existing features or only add new ones?
|
||||
- Are there obvious compilation or null safety issues?
|
||||
|
||||
### Second Pass: Architecture Deep-Dive
|
||||
|
||||
<thinking>
|
||||
Verify architectural integrity:
|
||||
1. Does this follow MVVM + UDF pattern?
|
||||
2. Is Hilt DI used correctly?
|
||||
3. Is state management proper (StateFlow, immutability)?
|
||||
4. Are modules organized correctly?
|
||||
5. Is error handling robust (Result types)?
|
||||
</thinking>
|
||||
|
||||
**4. MVVM + UDF Pattern Compliance:**
|
||||
- ViewModels properly structured?
|
||||
- State management using StateFlow?
|
||||
- Business logic in correct layer?
|
||||
|
||||
**5. Dependency Injection:**
|
||||
- Hilt DI used correctly?
|
||||
- Dependencies injected, not manually instantiated?
|
||||
- Proper scoping applied?
|
||||
|
||||
**6. Module Organization:**
|
||||
- Code placed in correct modules?
|
||||
- No circular dependencies introduced?
|
||||
- Proper separation of concerns?
|
||||
|
||||
**7. Error Handling:**
|
||||
- Using Result types, not exception-based handling?
|
||||
- Errors propagated correctly through layers?
|
||||
|
||||
### Third Pass: Details and Quality
|
||||
|
||||
<thinking>
|
||||
Check quality and completeness:
|
||||
1. Is code quality high? (null safety, documentation, naming)
|
||||
2. Are tests comprehensive? (unit + integration)
|
||||
3. Are there edge cases not covered?
|
||||
4. Is documentation clear?
|
||||
5. Are there any code smells or anti-patterns?
|
||||
</thinking>
|
||||
|
||||
**8. Testing:**
|
||||
- Unit tests for ViewModels and repositories?
|
||||
- Test coverage for edge cases and error scenarios?
|
||||
- Tests verify behavior, not implementation?
|
||||
|
||||
**9. Code Quality:**
|
||||
- Null safety handled properly?
|
||||
- Public APIs have KDoc documentation?
|
||||
- Naming follows project conventions?
|
||||
|
||||
**10. Security:**
|
||||
- Sensitive data encrypted properly?
|
||||
- Authentication/authorization handled correctly?
|
||||
- Zero-knowledge architecture preserved?
|
||||
|
||||
## Architecture Review
|
||||
|
||||
### MVVM Pattern Compliance
|
||||
|
||||
Read `reference/architectural-patterns.md` for detailed patterns.
|
||||
|
||||
**ViewModels must:**
|
||||
- Use `@HiltViewModel` annotation
|
||||
- Use `@Inject constructor`
|
||||
- Expose `StateFlow<T>`, NOT `MutableStateFlow<T>` publicly
|
||||
- Delegate business logic to Repository/Manager
|
||||
- Avoid direct Android framework dependencies (except ViewModel, SavedStateHandle)
|
||||
|
||||
**Common Violations:**
|
||||
```kotlin
|
||||
// ❌ BAD - Exposes mutable state
|
||||
class FeatureViewModel @Inject constructor() : ViewModel() {
|
||||
val state: MutableStateFlow<State> = MutableStateFlow(State.Initial)
|
||||
}
|
||||
|
||||
// ✅ GOOD - Exposes immutable state
|
||||
class FeatureViewModel @Inject constructor() : ViewModel() {
|
||||
private val _state = MutableStateFlow<State>(State.Initial)
|
||||
val state: StateFlow<State> = _state.asStateFlow()
|
||||
}
|
||||
|
||||
// ❌ BAD - Business logic in ViewModel
|
||||
fun onSubmit() {
|
||||
val encrypted = encryptionManager.encrypt(password) // Should be in Repository
|
||||
_state.value = State.Success
|
||||
}
|
||||
|
||||
// ✅ GOOD - Business logic in Repository, state updated via internal event
|
||||
fun onSubmit() {
|
||||
viewModelScope.launch {
|
||||
// The result of the async operation is captured
|
||||
val result = repository.submitData(password)
|
||||
// A single event is sent with the result, not updating state directly
|
||||
sendAction(FeatureAction.Internal.SubmissionComplete(result))
|
||||
}
|
||||
}
|
||||
|
||||
// The ViewModel has a handler that processes the internal event
|
||||
private fun handleInternalAction(action: FeatureAction.Internal) {
|
||||
when (action) {
|
||||
is FeatureAction.Internal.SubmissionComplete -> {
|
||||
// The event handler evaluates the result and updates state
|
||||
action.result.fold(
|
||||
onSuccess = { _state.value = State.Success },
|
||||
onFailure = { _state.value = State.Error(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**UI Layer must:**
|
||||
- Only observe state, never modify
|
||||
- Pass user actions as events to ViewModel
|
||||
- Contain no business logic
|
||||
- Use existing UI components from `:ui` module where possible
|
||||
|
||||
### Hilt Dependency Injection
|
||||
|
||||
Reference: `docs/ARCHITECTURE.md#dependency-injection`
|
||||
|
||||
**Required Patterns:**
|
||||
- ViewModels: `@HiltViewModel` + `@Inject constructor`
|
||||
- Repositories: `@Inject constructor` on implementation
|
||||
- Inject interfaces, not concrete implementations
|
||||
- Modules must provide proper scoping (`@Singleton`, `@ViewModelScoped`)
|
||||
|
||||
**Common Violations:**
|
||||
```kotlin
|
||||
// ❌ BAD - Manual instantiation
|
||||
class FeatureViewModel : ViewModel() {
|
||||
private val repository = FeatureRepositoryImpl()
|
||||
}
|
||||
|
||||
// ✅ GOOD - Injected interface
|
||||
@HiltViewModel
|
||||
class FeatureViewModel @Inject constructor(
|
||||
private val repository: FeatureRepository // Interface, not implementation
|
||||
) : ViewModel()
|
||||
|
||||
// ❌ BAD - Injecting implementation
|
||||
class FeatureViewModel @Inject constructor(
|
||||
private val repository: FeatureRepositoryImpl // Should inject interface
|
||||
)
|
||||
|
||||
// ✅ GOOD - Interface injection
|
||||
class FeatureViewModel @Inject constructor(
|
||||
private val repository: FeatureRepository // Interface
|
||||
)
|
||||
```
|
||||
|
||||
### Module Organization
|
||||
|
||||
Reference: `docs/ARCHITECTURE.md#module-structure`
|
||||
|
||||
**Correct Placement:**
|
||||
- `:core` - Shared utilities (cryptography, analytics, logging)
|
||||
- `:data` - Repositories, database, domain models
|
||||
- `:network` - API clients, network utilities
|
||||
- `:ui` - Reusable Compose components, theme
|
||||
- `:app` - Feature screens, ViewModels, navigation
|
||||
- `:authenticator` - Authenticator app (separate from password manager)
|
||||
|
||||
**Check:**
|
||||
- UI code in `:ui` or `:app` modules
|
||||
- Data models in `:data`
|
||||
- Network clients in `:network`
|
||||
- No circular dependencies between modules
|
||||
|
||||
### Error Handling
|
||||
|
||||
Reference: `docs/ARCHITECTURE.md#error-handling`
|
||||
|
||||
**Required Pattern - Use Result types:**
|
||||
```kotlin
|
||||
// ✅ GOOD - Result type
|
||||
suspend fun fetchData(): Result<Data> = runCatching {
|
||||
apiService.getData()
|
||||
}
|
||||
|
||||
// ViewModel handles Result
|
||||
repository.fetchData().fold(
|
||||
onSuccess = { data -> _state.value = State.Success(data) },
|
||||
onFailure = { error -> _state.value = State.Error(error) }
|
||||
)
|
||||
|
||||
// ❌ BAD - Exception-based in business logic
|
||||
suspend fun fetchData(): Data {
|
||||
try {
|
||||
return apiService.getData()
|
||||
} catch (e: Exception) {
|
||||
throw FeatureException(e) // Don't throw in business logic
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Review
|
||||
|
||||
Reference: `docs/ARCHITECTURE.md#security`
|
||||
|
||||
**Critical Security Checks:**
|
||||
|
||||
- **Sensitive data encrypted**: Passwords, keys, tokens use Android Keystore or EncryptedSharedPreferences
|
||||
- **No plaintext secrets**: No passwords/keys in logs, memory dumps, or SharedPreferences
|
||||
- **Input validation**: All user-provided data validated and sanitized
|
||||
- **Authentication tokens**: Securely stored and transmitted
|
||||
- **Zero-knowledge architecture**: Encryption happens client-side, server never sees plaintext
|
||||
|
||||
**Red Flags:**
|
||||
```kotlin
|
||||
// ❌ CRITICAL - Plaintext storage
|
||||
sharedPreferences.edit {
|
||||
putString("pin", userPin) // Must use EncryptedSharedPreferences
|
||||
}
|
||||
|
||||
// ❌ CRITICAL - Logging sensitive data
|
||||
Log.d("Auth", "Password: $password") // Never log sensitive data
|
||||
|
||||
// ❌ CRITICAL - Weak encryption
|
||||
val cipher = Cipher.getInstance("DES") // Use AES-256-GCM
|
||||
|
||||
// ✅ GOOD - Keystore encryption
|
||||
val encryptedData = keystoreManager.encrypt(sensitiveData)
|
||||
secureStorage.store(encryptedData)
|
||||
```
|
||||
|
||||
**If security concerns found, classify as CRITICAL using `reference/priority-framework.md`**
|
||||
|
||||
## Testing Review
|
||||
|
||||
Reference: `reference/testing-patterns.md`
|
||||
|
||||
**Required Test Coverage:**
|
||||
|
||||
- **ViewModels**: Unit tests for state transitions, actions, error scenarios
|
||||
- **Repositories**: Unit tests for data transformations, error handling
|
||||
- **Business logic**: Unit tests for complex algorithms, calculations
|
||||
- **Edge cases**: Null inputs, empty states, network failures, concurrent operations
|
||||
|
||||
**Test Quality:**
|
||||
```kotlin
|
||||
// ✅ GOOD - Tests behavior
|
||||
@Test
|
||||
fun `when login succeeds then state updates to success`() = runTest {
|
||||
val viewModel = LoginViewModel(mockRepository)
|
||||
|
||||
coEvery { mockRepository.login(any(), any()) } returns Result.success(User())
|
||||
|
||||
viewModel.onLoginClicked("user", "pass")
|
||||
|
||||
viewModel.state.test {
|
||||
assertEquals(LoginState.Success, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ BAD - Tests implementation
|
||||
@Test
|
||||
fun `repository is called with correct parameters`() {
|
||||
// This is testing internal implementation, not behavior
|
||||
}
|
||||
```
|
||||
|
||||
**Testing Frameworks:**
|
||||
- JUnit 5 for test structure
|
||||
- MockK for mocking
|
||||
- Turbine for Flow testing
|
||||
- Kotlinx-coroutines-test for coroutine testing
|
||||
|
||||
## Code Quality
|
||||
|
||||
### Null Safety
|
||||
|
||||
- No `!!` (non-null assertion) without clear safety guarantee
|
||||
- Platform types (from Java) handled with explicit nullability
|
||||
- Nullable types have proper null checks or use safe operators (`?.`, `?:`)
|
||||
|
||||
```kotlin
|
||||
// ❌ BAD - Unsafe assertion
|
||||
val result = apiService.getData()!! // Could crash
|
||||
|
||||
// ✅ GOOD - Safe handling
|
||||
val result = apiService.getData() ?: return State.Error("No data")
|
||||
|
||||
// ❌ BAD - Platform type unchecked
|
||||
val intent: Intent = getIntent() // Could be null from Java
|
||||
intent.getStringExtra("key") // Potential NPE
|
||||
|
||||
// ✅ GOOD - Explicit nullability
|
||||
val intent: Intent? = getIntent()
|
||||
intent?.getStringExtra("key")
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
- **Public APIs**: Have KDoc comments explaining purpose, parameters, return values
|
||||
- **Complex algorithms**: Explained in comments
|
||||
- **Non-obvious behavior**: Documented with rationale
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Documented public API
|
||||
/**
|
||||
* Encrypts the given data using AES-256-GCM with a key from Android Keystore.
|
||||
*
|
||||
* @param plaintext The data to encrypt
|
||||
* @return Result containing encrypted data or encryption error
|
||||
*/
|
||||
suspend fun encrypt(plaintext: ByteArray): Result<EncryptedData>
|
||||
```
|
||||
|
||||
### Style Compliance
|
||||
|
||||
Reference: `docs/STYLE_AND_BEST_PRACTICES.md`
|
||||
|
||||
Only flag style issues if:
|
||||
- Not caught by linters (Detekt, ktlint)
|
||||
- Have architectural implications
|
||||
- Significantly impact readability
|
||||
|
||||
Skip minor formatting (spaces, line breaks, etc.) - linters handle this.
|
||||
|
||||
## Prioritizing Findings
|
||||
|
||||
Use `reference/priority-framework.md` to classify findings as Critical/Important/Suggested/Optional.
|
||||
|
||||
## Providing Feedback
|
||||
|
||||
Use `reference/review-psychology.md` for phrasing guidance.
|
||||
|
||||
**Key principles:**
|
||||
- **Ask questions** for design decisions: "Can we use the existing BitwardenTextField component here?"
|
||||
- **Be prescriptive** for clear violations: "Change MutableStateFlow to StateFlow (MVVM pattern requirement)"
|
||||
- **Explain rationale**: "This exposes mutable state, violating unidirectional data flow"
|
||||
- **Use I-statements**: "It's hard for me to understand this logic without comments"
|
||||
- **Avoid condescension**: Don't use "just", "simply", "obviously"
|
||||
|
||||
## Output Format
|
||||
|
||||
Follow the format guidance from `SKILL.md` Step 5 (concise summary with critical issues only, detailed inline comments with `<details>` tags).
|
||||
|
||||
See `examples/review-outputs.md` for comprehensive feature review example.
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE / REQUEST CHANGES
|
||||
|
||||
**Critical Issues** (if any):
|
||||
- [One-line summary of each critical blocking issue with file:line reference]
|
||||
|
||||
See inline comments for all issue details.
|
||||
```
|
||||
260
.claude/skills/reviewing-changes/checklists/infrastructure.md
Normal file
260
.claude/skills/reviewing-changes/checklists/infrastructure.md
Normal file
@@ -0,0 +1,260 @@
|
||||
# Infrastructure Review Checklist
|
||||
|
||||
## Multi-Pass Strategy
|
||||
|
||||
### First Pass: Understand the Change
|
||||
|
||||
<thinking>
|
||||
Assess infrastructure change:
|
||||
1. What problem does this solve?
|
||||
2. Does this affect production builds, CI/CD, or dev workflow?
|
||||
3. What's the risk if this breaks?
|
||||
4. Can this be tested before merge?
|
||||
5. What's the rollback plan?
|
||||
</thinking>
|
||||
|
||||
**1. Identify the goal:**
|
||||
- What problem does this solve?
|
||||
- Is this optimization, fix, or new capability?
|
||||
- What's the expected impact?
|
||||
|
||||
**2. Assess risk:**
|
||||
- Does this affect production builds?
|
||||
- Could this break CI/CD pipelines?
|
||||
- Impact on developer workflow?
|
||||
|
||||
**3. Performance implications:**
|
||||
- Will builds be faster or slower?
|
||||
- CI time impact?
|
||||
- Resource usage changes?
|
||||
|
||||
### Second Pass: Verify Implementation
|
||||
|
||||
<thinking>
|
||||
Verify configuration and impact:
|
||||
1. Is the configuration syntax valid?
|
||||
2. Are secrets/credentials handled securely?
|
||||
3. What's the impact on build times and CI performance?
|
||||
4. How will this affect the team's workflow?
|
||||
5. Is there adequate testing/validation?
|
||||
</thinking>
|
||||
|
||||
**4. Configuration correctness:**
|
||||
- Syntax valid?
|
||||
- References correct?
|
||||
- Secrets/credentials handled securely?
|
||||
|
||||
**5. Impact analysis:**
|
||||
- What workflows/builds are affected?
|
||||
- Rollback plan if this breaks?
|
||||
- Documentation for team?
|
||||
|
||||
**6. Testing strategy:**
|
||||
- How can this be tested before merge?
|
||||
- Canary/gradual rollout possible?
|
||||
- Monitoring for issues post-merge?
|
||||
|
||||
## What to CHECK
|
||||
|
||||
✅ **Configuration Correctness**
|
||||
- YAML/Groovy syntax valid
|
||||
- File references correct
|
||||
- Version numbers/tags valid
|
||||
- Conditional logic sound
|
||||
|
||||
✅ **Security**
|
||||
- No hardcoded secrets or credentials
|
||||
- GitHub secrets used properly
|
||||
- Permissions appropriately scoped
|
||||
- No sensitive data in logs
|
||||
|
||||
✅ **Performance Impact**
|
||||
- Build time implications understood
|
||||
- CI queue time impact assessed
|
||||
- Resource usage reasonable
|
||||
|
||||
✅ **Rollback Plan**
|
||||
- Can this be reverted easily?
|
||||
- Dependencies on other changes?
|
||||
- Gradual rollout possible?
|
||||
|
||||
✅ **Documentation**
|
||||
- Changes documented for team?
|
||||
- README or CONTRIBUTING updated?
|
||||
- Breaking changes clearly noted?
|
||||
|
||||
## What to SKIP
|
||||
|
||||
❌ **Bikeshedding Configuration** - Unless clear performance/maintenance benefit
|
||||
❌ **Over-Optimization** - Unless current system has proven problems
|
||||
❌ **Suggesting Major Rewrites** - Unless current approach is fundamentally broken
|
||||
|
||||
## Red Flags
|
||||
|
||||
🚩 **Hardcoded secrets** - Use GitHub secrets or secure storage
|
||||
🚩 **No rollback plan** - Critical infrastructure should be revertible
|
||||
🚩 **Untested changes** - CI changes should be validated
|
||||
🚩 **Breaking changes without notice** - Team needs advance warning
|
||||
🚩 **Performance regression** - Builds shouldn't get significantly slower
|
||||
|
||||
## Key Questions to Ask
|
||||
|
||||
Use `reference/review-psychology.md` for phrasing:
|
||||
|
||||
- "What's the rollback plan if this breaks CI?"
|
||||
- "Can we test this on a feature branch before main?"
|
||||
- "Will this impact build times? By how much?"
|
||||
- "Should this be documented in CONTRIBUTING.md?"
|
||||
|
||||
## Common Infrastructure Patterns
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
# ✅ GOOD - Secure, clear, tested
|
||||
name: Build and Test
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30 # Prevent runaway builds
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run tests
|
||||
env:
|
||||
API_KEY: ${{ secrets.API_KEY }} # Secure secret usage
|
||||
run: ./gradlew test
|
||||
|
||||
# ❌ BAD - Insecure, unclear
|
||||
name: Build
|
||||
on: push # Too broad, runs on all branches
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
# No timeout - could run forever
|
||||
steps:
|
||||
- run: |
|
||||
export API_KEY="hardcoded_key_here" # Hardcoded secret!
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
### Gradle Configuration
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Clear, maintainable
|
||||
dependencies {
|
||||
implementation(libs.androidx.core.ktx) // Version catalog
|
||||
implementation(libs.hilt.android)
|
||||
|
||||
testImplementation(libs.junit5)
|
||||
testImplementation(libs.mockk)
|
||||
}
|
||||
|
||||
// ❌ BAD - Hardcoded versions
|
||||
dependencies {
|
||||
implementation("androidx.core:core-ktx:1.12.0") // Hardcoded version
|
||||
implementation("com.google.dagger:hilt-android:2.48")
|
||||
}
|
||||
```
|
||||
|
||||
### Build Optimization
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Parallel, cached
|
||||
tasks.register("checkAll") {
|
||||
dependsOn("detekt", "ktlintCheck", "testStandardDebug")
|
||||
group = "verification"
|
||||
description = "Run all checks in parallel"
|
||||
|
||||
// Enable caching for faster builds
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
// ❌ BAD - Sequential, no caching
|
||||
tasks.register("checkAll") {
|
||||
doLast {
|
||||
exec { commandLine("./gradlew", "detekt") }
|
||||
exec { commandLine("./gradlew", "ktlintCheck") } // Sequential
|
||||
exec { commandLine("./gradlew", "test") }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Prioritizing Findings
|
||||
|
||||
Use `reference/priority-framework.md` to classify findings as Critical/Important/Suggested/Optional.
|
||||
|
||||
## Output Format
|
||||
|
||||
Follow the format guidance from `SKILL.md` Step 5 (concise summary with critical issues only, detailed inline comments with `<details>` tags).
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE / REQUEST CHANGES
|
||||
|
||||
**Critical Issues** (if any):
|
||||
- [One-line summary of each critical blocking issue with file:line reference]
|
||||
|
||||
See inline comments for all issue details.
|
||||
```
|
||||
|
||||
## Example Review
|
||||
|
||||
```markdown
|
||||
## Summary
|
||||
Optimizes CI build by parallelizing test execution and caching dependencies
|
||||
|
||||
Impact: Estimated 40% reduction in CI time (12 min → 7 min per build)
|
||||
|
||||
## Critical Issues
|
||||
None
|
||||
|
||||
## Suggested Improvements
|
||||
|
||||
**.github/workflows/build.yml:23** - Add timeout for safety
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30 # Prevent builds from hanging
|
||||
steps:
|
||||
# ...
|
||||
```
|
||||
This prevents runaway builds if something goes wrong.
|
||||
|
||||
**.github/workflows/build.yml:45** - Consider matrix strategy for module tests
|
||||
Can we run module tests in parallel using a matrix strategy?
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
module: [app, data, network, ui]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: ./gradlew :${{ matrix.module }}:test
|
||||
```
|
||||
This could further reduce CI time.
|
||||
|
||||
**build.gradle.kts:12** - Document caching strategy
|
||||
Can we add a comment explaining the caching configuration?
|
||||
Future maintainers will appreciate understanding why these specific cache keys are used.
|
||||
|
||||
## Good Practices
|
||||
- Proper use of GitHub Actions cache
|
||||
- Parallel test execution
|
||||
- Version catalog for dependencies
|
||||
|
||||
## Action Items
|
||||
1. Add timeout to build workflow
|
||||
2. Consider matrix strategy for further parallelization
|
||||
3. Document caching strategy in build file
|
||||
|
||||
## Rollback Plan
|
||||
If CI breaks:
|
||||
- Revert commit: `git revert [commit-hash]`
|
||||
- Previous workflow available at: `.github/workflows/build.yml@main^`
|
||||
- Monitor CI times at: https://github.com/[org]/[repo]/actions
|
||||
```
|
||||
234
.claude/skills/reviewing-changes/checklists/refactoring.md
Normal file
234
.claude/skills/reviewing-changes/checklists/refactoring.md
Normal file
@@ -0,0 +1,234 @@
|
||||
# Refactoring Review Checklist
|
||||
|
||||
## Multi-Pass Strategy
|
||||
|
||||
### First Pass: Understand the Refactoring
|
||||
|
||||
<thinking>
|
||||
Analyze the refactoring scope:
|
||||
1. What pattern is being improved?
|
||||
2. Why is this refactoring needed?
|
||||
3. Does this change behavior or just structure?
|
||||
4. What's the scope? (files affected, migration completeness)
|
||||
5. What are the risks if something breaks?
|
||||
</thinking>
|
||||
|
||||
**1. Understand the goal:**
|
||||
- What pattern is being improved?
|
||||
- Why is this refactoring needed?
|
||||
- What's the scope of changes?
|
||||
|
||||
**2. Assess completeness:**
|
||||
- Are all instances refactored or just some?
|
||||
- Are there related areas that should also change?
|
||||
- Is the migration complete or partial?
|
||||
|
||||
**3. Risk assessment:**
|
||||
- Does this change behavior?
|
||||
- How many files affected?
|
||||
- Are tests updated to reflect changes?
|
||||
|
||||
### Second Pass: Verify Consistency
|
||||
|
||||
<thinking>
|
||||
Verify refactoring quality:
|
||||
1. Is the new pattern applied consistently throughout?
|
||||
2. Are there missed instances of the old pattern?
|
||||
3. Do tests still pass with same behavior?
|
||||
4. Is the migration complete or partial?
|
||||
5. Does this introduce any new issues?
|
||||
</thinking>
|
||||
|
||||
**4. Pattern consistency:**
|
||||
- Is the new pattern applied consistently throughout?
|
||||
- Are there missed instances of the old pattern?
|
||||
- Does this match established project patterns?
|
||||
|
||||
**5. Migration completeness:**
|
||||
- Old pattern fully removed or deprecated?
|
||||
- All usages updated?
|
||||
- Documentation updated?
|
||||
|
||||
**6. Test coverage:**
|
||||
- Do tests still pass?
|
||||
- Are tests refactored to match?
|
||||
- Does behavior remain unchanged?
|
||||
|
||||
## What to CHECK
|
||||
|
||||
✅ **Pattern Consistency**
|
||||
- New pattern applied consistently across all touched code
|
||||
- Follows established project patterns (MVVM, DI, error handling)
|
||||
- No mix of old and new patterns
|
||||
|
||||
✅ **Migration Completeness**
|
||||
- All instances of old pattern updated?
|
||||
- Deprecated methods removed or marked @Deprecated?
|
||||
- Related code also updated (tests, docs)?
|
||||
|
||||
✅ **Behavior Preservation**
|
||||
- Refactoring doesn't change behavior
|
||||
- Tests still pass
|
||||
- Edge cases still handled
|
||||
|
||||
✅ **Deprecation Strategy** (if applicable)
|
||||
- Old APIs marked @Deprecated with migration guidance
|
||||
- Replacement clearly documented
|
||||
- Timeline for removal specified
|
||||
|
||||
## What to SKIP
|
||||
|
||||
❌ **Suggesting Additional Refactorings** - Unless directly related to current changes
|
||||
❌ **Scope Creep** - Don't request refactoring of untouched code
|
||||
❌ **Perfection** - Better code is better than perfect code
|
||||
|
||||
## Red Flags
|
||||
|
||||
🚩 **Incomplete migration** - Mix of old and new patterns
|
||||
🚩 **Behavior changes** - Refactoring shouldn't change behavior
|
||||
🚩 **Broken tests** - Tests should be updated to match refactoring
|
||||
🚩 **Undocumented pattern** - New pattern should be clear to team
|
||||
|
||||
## Key Questions to Ask
|
||||
|
||||
Use `reference/review-psychology.md` for phrasing:
|
||||
|
||||
- "I see the old pattern still used in [file:line] - should that be updated too?"
|
||||
- "Can we add @Deprecated to the old method with migration guidance?"
|
||||
- "How do we ensure this behavior remains the same?"
|
||||
- "Should this pattern be documented in ARCHITECTURE.md?"
|
||||
|
||||
## Common Refactoring Patterns
|
||||
|
||||
### Extract Interface/Repository
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Complete migration
|
||||
interface FeatureRepository {
|
||||
suspend fun getData(): Result<Data>
|
||||
}
|
||||
|
||||
class FeatureRepositoryImpl @Inject constructor(
|
||||
private val apiService: FeatureApiService
|
||||
) : FeatureRepository {
|
||||
override suspend fun getData(): Result<Data> = runCatching {
|
||||
apiService.fetchData()
|
||||
}
|
||||
}
|
||||
|
||||
// All usages updated to inject interface
|
||||
class FeatureViewModel @Inject constructor(
|
||||
private val repository: FeatureRepository // Interface
|
||||
) : ViewModel()
|
||||
|
||||
// ❌ BAD - Incomplete migration
|
||||
// Some files still inject FeatureRepositoryImpl directly
|
||||
```
|
||||
|
||||
### Modernize Error Handling
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Complete migration
|
||||
// Old exception-based removed
|
||||
suspend fun fetchData(): Result<Data> = runCatching {
|
||||
apiService.getData()
|
||||
}
|
||||
|
||||
// All call sites updated
|
||||
repository.fetchData().fold(
|
||||
onSuccess = { /* handle */ },
|
||||
onFailure = { /* handle */ }
|
||||
)
|
||||
|
||||
// ❌ BAD - Mixed patterns
|
||||
// Some functions use Result, others still throw exceptions
|
||||
```
|
||||
|
||||
### Extract Reusable Component
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Complete extraction
|
||||
// Component moved to :ui module
|
||||
@Composable
|
||||
fun BitwardenButton(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
)
|
||||
|
||||
// All usages updated to use new component
|
||||
// Old inline button implementations removed
|
||||
|
||||
// ❌ BAD - Incomplete extraction
|
||||
// Some screens use new component, others still have inline implementation
|
||||
```
|
||||
|
||||
## Prioritizing Findings
|
||||
|
||||
Use `reference/priority-framework.md` to classify findings as Critical/Important/Suggested/Optional.
|
||||
|
||||
## Output Format
|
||||
|
||||
Follow the format guidance from `SKILL.md` Step 5 (concise summary with critical issues only, detailed inline comments with `<details>` tags).
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE / REQUEST CHANGES
|
||||
|
||||
**Critical Issues** (if any):
|
||||
- [One-line summary of each critical blocking issue with file:line reference]
|
||||
|
||||
See inline comments for all issue details.
|
||||
```
|
||||
|
||||
## Example Review
|
||||
|
||||
```markdown
|
||||
## Summary
|
||||
Refactors authentication flow to use Repository pattern instead of direct Manager access
|
||||
|
||||
Scope: 12 files changed, 8 ViewModels updated, Repository interface extracted
|
||||
|
||||
## Critical Issues
|
||||
None - behavior preserved, tests passing
|
||||
|
||||
## Suggested Improvements
|
||||
|
||||
**app/vault/VaultViewModel.kt:89** - Old pattern still used
|
||||
This ViewModel still injects AuthManager directly. Should it use AuthRepository like the others?
|
||||
```kotlin
|
||||
// Current
|
||||
class VaultViewModel @Inject constructor(
|
||||
private val authManager: AuthManager // Old pattern
|
||||
)
|
||||
|
||||
// Should be
|
||||
class VaultViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository // New pattern
|
||||
)
|
||||
```
|
||||
|
||||
**data/auth/AuthManager.kt:1** - Add deprecation notice
|
||||
Can we add @Deprecated to AuthManager to guide future development?
|
||||
```kotlin
|
||||
@Deprecated(
|
||||
message = "Use AuthRepository interface instead",
|
||||
replaceWith = ReplaceWith("AuthRepository"),
|
||||
level = DeprecationLevel.WARNING
|
||||
)
|
||||
class AuthManager
|
||||
```
|
||||
|
||||
**docs/ARCHITECTURE.md** - Document the new pattern
|
||||
Should we update the architecture docs to reflect this Repository pattern?
|
||||
The current docs still reference AuthManager as the recommended approach.
|
||||
|
||||
## Good Practices
|
||||
- Repository interface clearly defined
|
||||
- All data access methods use Result types
|
||||
- Tests updated to match new pattern
|
||||
|
||||
## Action Items
|
||||
1. Update VaultViewModel to use AuthRepository
|
||||
2. Add @Deprecated to AuthManager with migration guidance
|
||||
3. Update ARCHITECTURE.md to document Repository pattern
|
||||
```
|
||||
243
.claude/skills/reviewing-changes/checklists/ui-refinement.md
Normal file
243
.claude/skills/reviewing-changes/checklists/ui-refinement.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# UI Refinement Review Checklist
|
||||
|
||||
## Multi-Pass Strategy
|
||||
|
||||
### First Pass: Visual Changes
|
||||
|
||||
<thinking>
|
||||
Analyze the UI changes:
|
||||
1. What visual/UX problem is being solved?
|
||||
2. Are there designs or screenshots to reference?
|
||||
3. Is this affecting existing screens or new ones?
|
||||
4. What's the scope of visual changes?
|
||||
5. Are design tokens (colors, spacing, typography) being used correctly?
|
||||
</thinking>
|
||||
|
||||
**1. Understand the changes:**
|
||||
- What visual/UX problem is being solved?
|
||||
- Are there designs or screenshots to reference?
|
||||
- Is this a bug fix or enhancement?
|
||||
|
||||
**2. Component usage:**
|
||||
- Using existing components from `:ui` module?
|
||||
- Any new custom components created?
|
||||
- Could existing components be reused?
|
||||
|
||||
### Second Pass: Implementation Review
|
||||
|
||||
<thinking>
|
||||
Check implementation quality:
|
||||
1. Are Compose best practices followed?
|
||||
2. Is state hoisting applied correctly?
|
||||
3. Are existing components reused where possible?
|
||||
4. Is accessibility properly handled?
|
||||
5. Does this follow design system patterns?
|
||||
</thinking>
|
||||
|
||||
**3. Compose best practices:**
|
||||
- Composables properly structured?
|
||||
- State hoisted correctly?
|
||||
- Preview composables included?
|
||||
|
||||
**4. Accessibility:**
|
||||
- Content descriptions for images/icons?
|
||||
- Semantic properties for screen readers?
|
||||
- Touch targets meet minimum size (48dp)?
|
||||
|
||||
**5. Design consistency:**
|
||||
- Using theme colors, spacing, typography?
|
||||
- Consistent with other screens?
|
||||
- Responsive to different screen sizes?
|
||||
|
||||
## What to CHECK
|
||||
|
||||
✅ **Compose Best Practices**
|
||||
- Composables are stateless where possible
|
||||
- State hoisting follows patterns
|
||||
- Side effects (LaunchedEffect, DisposableEffect) used correctly
|
||||
- Preview composables provided for development
|
||||
|
||||
✅ **Component Reuse**
|
||||
- Using existing BitwardenButton, BitwardenTextField, etc.?
|
||||
- Could custom UI be replaced with existing components?
|
||||
- New reusable components placed in `:ui` module?
|
||||
|
||||
✅ **Accessibility**
|
||||
- `contentDescription` for icons and images
|
||||
- `semantics` for custom interactions
|
||||
- Sufficient contrast ratios
|
||||
- Touch targets ≥ 48dp minimum
|
||||
|
||||
✅ **Design Consistency**
|
||||
- Using `BitwardenTheme` colors (not hardcoded)
|
||||
- Using `BitwardenTheme` spacing (16.dp, 8.dp, etc.)
|
||||
- Using `BitwardenTheme` typography styles
|
||||
- Consistent with existing screen patterns
|
||||
|
||||
✅ **Responsive Design**
|
||||
- Handles different screen sizes?
|
||||
- Scrollable content where appropriate?
|
||||
- Landscape orientation considered?
|
||||
|
||||
## What to SKIP
|
||||
|
||||
❌ **Deep Architecture Review** - Unless ViewModel changes are substantial
|
||||
❌ **Business Logic Review** - Focus is on presentation, not logic
|
||||
❌ **Security Review** - Unless UI exposes sensitive data improperly
|
||||
|
||||
## Red Flags
|
||||
|
||||
🚩 **Duplicating existing components** - Should reuse from `:ui` module
|
||||
🚩 **Hardcoded colors/dimensions** - Should use theme
|
||||
🚩 **Missing accessibility properties** - Critical for screen readers
|
||||
🚩 **State management in UI** - Should be hoisted to ViewModel
|
||||
|
||||
## Key Questions to Ask
|
||||
|
||||
Use `reference/review-psychology.md` for phrasing:
|
||||
|
||||
- "Can we use BitwardenButton here instead of this custom button?"
|
||||
- "Should this color come from BitwardenTheme instead of being hardcoded?"
|
||||
- "How will this look on a small screen?"
|
||||
- "Is there a contentDescription for this icon?"
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Composable Structure
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Stateless, hoisted state
|
||||
@Composable
|
||||
fun FeatureScreen(
|
||||
state: FeatureState,
|
||||
onActionClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
// UI rendering only
|
||||
}
|
||||
|
||||
// ❌ BAD - Business state in composable
|
||||
@Composable
|
||||
fun FeatureScreen() {
|
||||
var userData by remember { mutableStateOf<User?>(null) } // Business state should be in ViewModel
|
||||
var isLoading by remember { mutableStateOf(false) } // App state should be in ViewModel
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ OK - UI-local state in composable
|
||||
@Composable
|
||||
fun LoginForm(onSubmit: (String, String) -> Unit) {
|
||||
var username by remember { mutableStateOf("") } // UI-local input state is fine
|
||||
var password by remember { mutableStateOf("") }
|
||||
// Hoist only as high as needed
|
||||
}
|
||||
```
|
||||
|
||||
### Theme Usage
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Using theme
|
||||
Text(
|
||||
text = "Title",
|
||||
style = BitwardenTheme.typography.titleLarge,
|
||||
color = BitwardenTheme.colorScheme.primary
|
||||
)
|
||||
|
||||
// Design system uses 4.dp increments (4, 8, 12, 16, 24, 32, etc.)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// ❌ BAD - Hardcoded
|
||||
Text(
|
||||
text = "Title",
|
||||
style = TextStyle(fontSize = 24.sp, fontWeight = FontWeight.Bold), // Should use theme
|
||||
color = Color(0xFF0000FF) // Should use theme color
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(17.dp)) // Non-standard spacing
|
||||
```
|
||||
|
||||
### Accessibility
|
||||
|
||||
```kotlin
|
||||
// ✅ GOOD - Interactive element with description
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_password),
|
||||
contentDescription = "Password visibility toggle",
|
||||
modifier = Modifier.clickable { onToggle() }
|
||||
)
|
||||
|
||||
// ✅ GOOD - Decorative icon with explicit null
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_check),
|
||||
contentDescription = null, // Decorative icon next to descriptive text
|
||||
tint = BitwardenTheme.colorScheme.success
|
||||
)
|
||||
|
||||
// ❌ BAD - Interactive element missing description
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_delete),
|
||||
contentDescription = null, // Interactive elements need descriptions
|
||||
modifier = Modifier.clickable { onDelete() }
|
||||
)
|
||||
```
|
||||
|
||||
## Prioritizing Findings
|
||||
|
||||
Use `reference/priority-framework.md` to classify findings as Critical/Important/Suggested/Optional.
|
||||
|
||||
## Output Format
|
||||
|
||||
Follow the format guidance from `SKILL.md` Step 5 (concise summary with critical issues only, detailed inline comments with `<details>` tags).
|
||||
|
||||
```markdown
|
||||
**Overall Assessment:** APPROVE / REQUEST CHANGES
|
||||
|
||||
**Critical Issues** (if any):
|
||||
- [One-line summary of each critical blocking issue with file:line reference]
|
||||
|
||||
See inline comments for all issue details.
|
||||
```
|
||||
|
||||
## Example Review
|
||||
|
||||
```markdown
|
||||
## Summary
|
||||
Updates login screen layout for improved visual hierarchy and touch targets
|
||||
|
||||
## Critical Issues
|
||||
None
|
||||
|
||||
## Suggested Improvements
|
||||
|
||||
**app/auth/LoginScreen.kt:67** - Can we use BitwardenTextField?
|
||||
This custom text field looks very similar to `ui/components/BitwardenTextField.kt:89`.
|
||||
Would using the existing component maintain consistency?
|
||||
|
||||
**app/auth/LoginScreen.kt:123** - Add contentDescription
|
||||
```kotlin
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_visibility),
|
||||
contentDescription = "Show password", // Add for accessibility
|
||||
modifier = Modifier.clickable { onToggleVisibility() }
|
||||
)
|
||||
```
|
||||
|
||||
**app/auth/LoginScreen.kt:145** - Use design system spacing
|
||||
```kotlin
|
||||
// Current
|
||||
Spacer(modifier = Modifier.height(17.dp))
|
||||
|
||||
// Design system uses 4.dp increments (4, 8, 12, 16, 24, 32, etc.)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
```
|
||||
|
||||
## Good Practices
|
||||
- Proper state hoisting to ViewModel
|
||||
- Preview composables included
|
||||
- Responsive layout with ScrollableColumn
|
||||
|
||||
## Action Items
|
||||
1. Evaluate using BitwardenTextField for consistency
|
||||
2. Add contentDescription for visibility icon
|
||||
3. Use standard 16.dp spacing
|
||||
```
|
||||
Reference in New Issue
Block a user