fix(validation): satisfy quality gate checks

- add root test script that runs mobile jest
- adjust hook usage to satisfy rules-of-hooks
- document validation commands for operators
This commit is contained in:
jjbrunton committed 2026-01-26 14:32:23 +00:00
1 parent 1370576dd5
commit 368399f463
7 files changed
+99 -37

No files matched your search

+8 -5
View File
@@ -113,7 +113,7 @@
{ {
"id": "US-004", "id": "US-004",
"title": "Refactor oversized hooks/services/utils", "title": "Refactor oversized hooks/services/utils",
"status": "in_progress", "status": "done",
"dependsOn": [ "dependsOn": [
"US-001" "US-001"
], ],
@@ -125,13 +125,13 @@
"All previous exports remain available or are re-exported from the original entry point" "All previous exports remain available or are re-exported from the original entry point"
], ],
"startedAt": "2026-01-26T14:22:32.363863+00:00", "startedAt": "2026-01-26T14:22:32.363863+00:00",
"completedAt": null, "completedAt": "2026-01-26T14:28:08.569075+00:00",
"updatedAt": "2026-01-26T14:22:32.363979+00:00" "updatedAt": "2026-01-26T14:28:08.568972+00:00"
}, },
{ {
"id": "US-005", "id": "US-005",
"title": "Validate refactor quality gates", "title": "Validate refactor quality gates",
"status": "open", "status": "in_progress",
"dependsOn": [ "dependsOn": [
"US-002", "US-002",
"US-003", "US-003",
@@ -142,7 +142,10 @@
"Run `npm test`, `npm run lint`, and `npm run typecheck` successfully", "Run `npm test`, `npm run lint`, and `npm run typecheck` successfully",
"Example: all tests pass without modifications to test expectations", "Example: all tests pass without modifications to test expectations",
"Negative case: if a check fails, refactor is incomplete and must be fixed before completion" "Negative case: if a check fails, refactor is incomplete and must be fixed before completion"
] ],
"startedAt": "2026-01-26T14:28:10.644821+00:00",
"completedAt": null,
"updatedAt": "2026-01-26T14:28:10.644945+00:00"
} }
] ]
} }
+9
View File
@@ -1,6 +1,7 @@
# Activity Log # Activity Log
## Run Summary ## Run Summary
- 2026-01-26 14:28:08 | run=20260126-140911-55357 | iter=2 | mode=build | story=US-004 | duration=336s | status=success
- 2026-01-26 14:22:30 | run=20260126-140911-55357 | iter=1 | mode=build | story=US-003 | duration=799s | status=success - 2026-01-26 14:22:30 | run=20260126-140911-55357 | iter=1 | mode=build | story=US-003 | duration=799s | status=success
- 2026-01-25 21:09:07 | run=20260125-204012-65223 | iter=25 | mode=build | story=US-003 | duration=0s | status=error - 2026-01-25 21:09:07 | run=20260125-204012-65223 | iter=25 | mode=build | story=US-003 | duration=0s | status=error
- 2026-01-25 21:09:04 | run=20260125-204012-65223 | iter=24 | mode=build | story=US-003 | duration=0s | status=error - 2026-01-25 21:09:04 | run=20260125-204012-65223 | iter=24 | mode=build | story=US-003 | duration=0s | status=error
@@ -101,3 +102,11 @@
[2026-01-26 14:26:13] Ran tests and build for US-004 [2026-01-26 14:26:13] Ran tests and build for US-004
[2026-01-26 14:26:51] Updated progress log for US-004 [2026-01-26 14:26:51] Updated progress log for US-004
[2026-01-26 14:27:24] Committed US-004 changes [2026-01-26 14:27:24] Committed US-004 changes
[2026-01-26 14:28:08] ITERATION 2 end (duration=336s)
[2026-01-26 14:28:10] ITERATION 3 start (mode=build story=US-005)
[2026-01-26 14:28:59] Start US-005 validation run (manual log; helper missing)
[2026-01-26 14:29:29] Added root test script for US-005
[2026-01-26 14:30:41] Fixed lint hook violations for US-005
[2026-01-26 14:31:01] Ran npm test, lint, typecheck, build for US-005
[2026-01-26 14:31:14] Added AGENTS.md operational notes
[2026-01-26 14:32:00] Re-ran npm test after lint fixes
@@ -0,0 +1,32 @@
# Ralph Run Summary
- Run ID: 20260126-140911-55357
- Iteration: 2
- Mode: build
- Story: US-004: Refactor oversized hooks/services/utils
- Started: 2026-01-26 14:22:32
- Ended: 2026-01-26 14:28:08
- Duration: 336s
- Status: success
- Log: /Users/jjbrunton/Projects/Sauci/.ralph/runs/run-20260126-140911-55357-iter-2.log
## Git
- Head (before): 70449659cf1ded7041b71ecf07aa2e7bc76f8346
- Head (after): 1370576dd59180f3b13e0a8d99255dfa96210d60
### Commits
- 1370576 chore(ralph): log commit action
- 6957502 chore(ralph): update progress logs
- 5a9defb refactor(swipe): split useSwipeScreen helpers
### Changed Files (commits)
- .agents/tasks/prd-mobile-refactor.json
- .ralph/activity.log
- .ralph/progress.md
- .ralph/runs/run-20260126-140911-55357-iter-1.md
- apps/mobile/src/features/swipe/hooks/useSwipeScreen.ts
- apps/mobile/src/features/swipe/utils/useSwipeScreen-helpers.ts
### Uncommitted Changes
- .ralph/activity.log
+7
View File
@@ -0,0 +1,7 @@
# AGENTS
## Verification
- npm test (runs mobile Jest suite)
- npm run lint
- npm run typecheck
- npm run build
@@ -13,6 +13,7 @@ import Animated, {
Easing, Easing,
FadeInDown, FadeInDown,
FadeIn, FadeIn,
type SharedValue,
} from "react-native-reanimated"; } from "react-native-reanimated";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { colors, gradients, radius, shadows, typography, spacing, animations } from "../../theme"; import { colors, gradients, radius, shadows, typography, spacing, animations } from "../../theme";
@@ -574,8 +575,13 @@ function PreviewContent({
// Audio level visualization component // Audio level visualization component
function AudioLevelBars({ isActive }: { isActive: boolean }) { function AudioLevelBars({ isActive }: { isActive: boolean }) {
const bars = 5; const barAnimations = [
const barAnimations = Array.from({ length: bars }, () => useSharedValue(0.3)); useSharedValue(0.3),
useSharedValue(0.3),
useSharedValue(0.3),
useSharedValue(0.3),
useSharedValue(0.3),
];
useEffect(() => { useEffect(() => {
if (isActive) { if (isActive) {
@@ -605,22 +611,25 @@ function AudioLevelBars({ isActive }: { isActive: boolean }) {
return ( return (
<View style={styles.audioLevelContainer}> <View style={styles.audioLevelContainer}>
{barAnimations.map((anim, index) => { {barAnimations.map((anim, index) => (
const barStyle = useAnimatedStyle(() => ({ <AudioLevelBar key={index} anim={anim} />
height: interpolate(anim.value, [0, 1], [8, 40]), ))}
}));
return (
<Animated.View
key={index}
style={[styles.audioLevelBar, barStyle]}
/>
);
})}
</View> </View>
); );
} }
function AudioLevelBar({ anim }: { anim: SharedValue<number> }) {
const barStyle = useAnimatedStyle(() => ({
height: interpolate(anim.value, [0, 1], [8, 40]),
}));
return (
<Animated.View
style={[styles.audioLevelBar, barStyle]}
/>
);
}
// Record button component // Record button component
function RecordButton({ onPress }: { onPress: () => void }) { function RecordButton({ onPress }: { onPress: () => void }) {
const buttonScale = useSharedValue(1); const buttonScale = useSharedValue(1);
@@ -32,22 +32,7 @@ const MessageContentComponent: React.FC<MessageContentProps> = ({
onImagePress, onImagePress,
onVideoFullScreen, onVideoFullScreen,
}) => { }) => {
// Check if message was deleted for everyone const isDeleted = !!item.deleted_at;
if (item.deleted_at) {
return (
<View style={styles.deletedContainer}>
<Ionicons
name="ban-outline"
size={14}
color={colors.textTertiary}
/>
<Text style={styles.deletedText}>
{isMe ? 'You deleted this message' : 'This message was deleted'}
</Text>
</View>
);
}
const isVideo = item.media_type === 'video'; const isVideo = item.media_type === 'video';
const isViewed = !!item.media_viewed_at; const isViewed = !!item.media_viewed_at;
const isRecipientHidden = !isMe && !isViewed; const isRecipientHidden = !isMe && !isViewed;
@@ -58,7 +43,7 @@ const MessageContentComponent: React.FC<MessageContentProps> = ({
const [mediaError, setMediaError] = useState(false); const [mediaError, setMediaError] = useState(false);
useEffect(() => { useEffect(() => {
if (!item.media_path || isRecipientHidden) { if (isDeleted || !item.media_path || isRecipientHidden) {
setMediaUri(null); setMediaUri(null);
return; return;
} }
@@ -85,11 +70,27 @@ const MessageContentComponent: React.FC<MessageContentProps> = ({
}; };
fetchMediaUrl(); fetchMediaUrl();
}, [item.media_path, isRecipientHidden]); }, [item.media_path, isRecipientHidden, isDeleted]);
// Handle expired videos // Handle expired videos
const isExpired = !!item.media_expired; const isExpired = !!item.media_expired;
// Check if message was deleted for everyone
if (isDeleted) {
return (
<View style={styles.deletedContainer}>
<Ionicons
name="ban-outline"
size={14}
color={colors.textTertiary}
/>
<Text style={styles.deletedText}>
{isMe ? 'You deleted this message' : 'This message was deleted'}
</Text>
</View>
);
}
if (isExpired && isVideo) { if (isExpired && isVideo) {
return ( return (
<View> <View>
+1
View File
@@ -11,6 +11,7 @@
"dev": "turbo dev", "dev": "turbo dev",
"build": "turbo build", "build": "turbo build",
"lint": "turbo lint", "lint": "turbo lint",
"test": "npm --workspace apps/mobile test",
"clean": "turbo clean", "clean": "turbo clean",
"typecheck": "turbo typecheck" "typecheck": "turbo typecheck"
}, },