diff --git a/Ralph/prd.json b/Ralph/prd.json index 577b566..e019eb6 100644 --- a/Ralph/prd.json +++ b/Ralph/prd.json @@ -136,7 +136,7 @@ "Verify in browser using dev-browser skill" ], "priority": 7, - "passes": false, + "passes": true, "notes": "The connectionTimeout is set on line 117 of LoginScreen.tsx (2000ms independent timer). Remove it and add a useEffect that watches typingComplete — when true, setTimeout 500ms then setConnectionState('connected'). The dot animation can use a simple interval cycling dotCount 0→1→2→0. The LED glow box-shadow: '0 0 6px 1px rgba(220,38,38,0.4)' for red, '0 0 6px 1px rgba(5,150,105,0.4)' for green." }, { @@ -155,7 +155,7 @@ "Verify in browser using dev-browser skill" ], "priority": 8, - "passes": false, + "passes": true, "notes": "The canLogin variable is on line 43 of LoginScreen.tsx. Add a CSS class 'login-pulse-active' that applies the animation, and conditionally apply it when canLogin && !buttonPressed && !buttonHovered. The @keyframes could use: 0%,100% { transform: scale(1) } 50% { transform: scale(1.03) } with animation: login-pulse 1.5s ease-in-out infinite and a wrapper that adds 1.5s gaps (or use 0%,35%,65%,100% keyframe percentages to build in the pause)." }, { @@ -175,7 +175,7 @@ "Verify in browser using dev-browser skill" ], "priority": 9, - "passes": false, + "passes": true, "notes": "Currently LoginScreen has isExiting state that scales card to 1.03 and fades to opacity 0 (line 163). Extend this to also animate the overlay container. The overlay is the outer div with 'fixed inset-0' — animate its backdrop-filter and background-color. Use framer-motion animate for coordinated exit. The onComplete callback should fire after the full dissolve, not after the card fade." }, { @@ -193,7 +193,7 @@ "Verify in browser using dev-browser skill: app starts at boot, progresses through ECG, login with blur background and logo animation, arrives at dashboard" ], "priority": 10, - "passes": false, + "passes": true, "notes": "Simple revert of US-001. Phase state is on line 47 of App.tsx." } ] diff --git a/Ralph/progress.txt b/Ralph/progress.txt index db49d3a..d27a2f7 100644 --- a/Ralph/progress.txt +++ b/Ralph/progress.txt @@ -61,19 +61,77 @@ - `animated` prop: boolean, enables framer-motion reveal animation (1000ms total) - Logo animation: 500ms rise (green capsule) + 500ms fan-out (all three) = 1000ms total -### LoginScreen.tsx Key Lines (post US-004) +### LoginScreen.tsx Key Lines (post US-007) - Line 20: connectionState useState +- Line 21: dotCount useState (for animated trailing dots) - Line 43: canLogin derived state - Line 60-101: startLoginSequence (typing animation) -- Line 110-139: useEffect with connectionTimeout (2000ms) and startLoginSequence delay (1500ms / 400ms reduced motion) -- Line 145-409: JSX render (card, form, button, status indicator) -- Line 208-211: CvmisLogo with cssHeight="clamp(48px, 4vw, 64px)" animated=true -- Line 221: "CVMIS" title -- Line 232: "CV Management Information System" subtitle -- Line 350-382: Connection status indicator (6px dot, 10px text) +- Line 110-115: useEffect — connection transitions to green 500ms after typingComplete +- Line 118-126: useEffect — animated dot cycling (500ms interval) while connecting +- Line 128-150: useEffect — cursor blink + startLoginSequence delay (no more connectionTimeout) +- Line 370-405: Connection status indicator (10px LED dot with glow, 12px text) --- +## 2026-02-15 - US-010 +- Reverted initial Phase state from 'login' back to 'boot' in App.tsx line 47 +- Full flow verified: boot → ECG → login (with blur, logo, typing, connection indicator, pulse) → dissolve → dashboard +- Files changed: src/App.tsx +- **Learnings for future iterations:** + - Simple one-line revert as planned in US-001 + - The full boot→ECG→login sequence takes ~20 seconds before login screen appears +--- + +## 2026-02-15 - US-009 +- Changed outer overlay container from plain `
` to `` for animated exit +- On isExiting: overlay animates backgroundColor to transparent, backdropFilter from blur(20px) to blur(0px) over 600ms +- Card exit animation extended from 200ms to 400ms for smoother dissolve feel +- onComplete callback fires after 600ms dissolve (previously 200ms card exit) +- After dissolve completes, overlay removed from DOM and dashboard becomes interactive +- prefers-reduced-motion: instant transition (0ms for all timers) +- Files changed: src/components/LoginScreen.tsx +- Verified in browser: clicked login → spinner → card fades + overlay blur dissolves → dashboard revealed +- **Learnings for future iterations:** + - framer-motion can animate backdropFilter and backgroundColor on a motion.div via the animate prop + - The onComplete timeout (600ms) must match the overlay dissolve duration, not the card fade duration + - Card fade (400ms) finishes before overlay dissolve (600ms), creating a layered reveal effect + - WebkitBackdropFilter needs to be animated alongside backdropFilter for Safari +--- + +## 2026-02-15 - US-008 +- Added @keyframes login-pulse in index.css: scale 1→1.03→1 over 3s cycle (1.5s animation built into keyframe percentages with 1.5s pause) +- Added .login-pulse-active class that applies the animation infinitely +- Hover removes animation via CSS rule (.login-pulse-active:hover { animation: none }) +- Button gets login-pulse-active class when canLogin && !buttonPressed +- prefers-reduced-motion: .login-pulse-active { animation: none } in reduced motion media query +- Button opacity 0.6→1.0 transition preserved (existing behavior) +- Button still receives keyboard focus when enabled (existing behavior) +- Files changed: src/index.css, src/components/LoginScreen.tsx +- Verified in browser: button has login-pulse animation running (3s ease-in-out infinite), class applied correctly +- **Learnings for future iterations:** + - Used keyframe percentages (0%,60%,100% at scale(1), 30% at scale(1.03)) to build pause into a single animation rather than animation-delay + - CSS handles hover removal — no need for buttonHovered state in the class condition + - buttonPressed removes the class entirely (not just pauses), which is cleaner +--- + +## 2026-02-15 - US-007 +- Reworked connection status indicator: LED dot 6px→10px with glow box-shadow, text 10px→12px +- Removed independent 2000ms connectionTimeout timer +- Added useEffect that transitions to green 500ms after typingComplete becomes true +- Added animated trailing dots cycling '.', '..', '...' every 500ms while connecting +- Initial state: red LED + red text "Awaiting secure connection" with animated dots +- Connected state: green LED + green text "Secure connection established, awaiting login" +- 300ms smooth transition for color and box-shadow between states +- prefers-reduced-motion: no dot cycling, instant state changes +- Files changed: src/components/LoginScreen.tsx +- Verified in browser: red indicator with cycling dots visible during typing, transitions to green after typing completes +- **Learnings for future iterations:** + - dotCount state cycles 0→1→2→3→0 (4 states: no dots, '.', '..', '...') via modulo arithmetic + - Connection transition is now tied to typingComplete state, not an arbitrary timer + - The dot interval cleanup needs to happen in both the dedicated useEffect and the main cleanup + - LED glow uses rgba with 0.4 alpha for subtle effect matching project shadow conventions +--- + ## 2026-02-15 - US-006 - Rendered DashboardLayout (wrapped in DetailPanelProvider) behind LoginScreen during login phase in App.tsx - Changed LoginScreen overlay from solid #1A2B2A background to semi-transparent rgba(240, 245, 244, 0.7) with backdrop-filter: blur(20px) diff --git a/scripts/ralph/CLAUDE.md b/scripts/ralph/CLAUDE.md index f95bb92..5a02d8b 100644 --- a/scripts/ralph/CLAUDE.md +++ b/scripts/ralph/CLAUDE.md @@ -2,6 +2,10 @@ You are an autonomous coding agent working on a software project. +## CRITICAL: One Story Per Iteration + +You MUST complete exactly ONE user story and then STOP. Do NOT start a second story. After committing and updating progress, your job is done — output your summary and stop. + ## Your Task 1. Read the PRD at `prd.json` (in the same directory as this file) @@ -14,6 +18,7 @@ You are an autonomous coding agent working on a software project. 8. If checks pass, commit ALL changes with message: `feat: [Story ID] - [Story Title]` 9. Update the PRD to set `passes: true` for the completed story 10. Append your progress to `progress.txt` +11. **STOP.** Output a short summary and end your response. Do NOT pick up the next story. ## Progress Report Format @@ -89,16 +94,7 @@ If no browser tools are available, note in your progress report that manual brow ## Stop Condition -After completing a user story, check if ALL stories have `passes: true`. +After completing ONE user story, check if ALL stories now have `passes: true`. -If ALL stories are complete and passing, reply with: -COMPLETE - -If there are still stories with `passes: false`, end your response normally (another iteration will pick up the next story). - -## Important - -- Work on ONE story per iteration -- Commit frequently -- Keep CI green -- Read the Codebase Patterns section in progress.txt before starting +- If ALL stories are complete: reply with `COMPLETE` and stop. +- If stories remain: output a short summary of what you did and **STOP immediately**. Do NOT continue to the next story. The outer loop will spawn a fresh iteration for it. diff --git a/scripts/ralph/ralph.sh b/scripts/ralph/ralph.sh index 66967ec..60b1bf0 100755 --- a/scripts/ralph/ralph.sh +++ b/scripts/ralph/ralph.sh @@ -146,9 +146,9 @@ for i in $(seq 1 $MAX_ITERATIONS); do ELAPSED_SEC=$((ELAPSED % 60)) printf " \033[0;90mFinished: $(date +%H:%M:%S) (elapsed: ${ELAPSED_MIN}m${ELAPSED_SEC}s)\033[0m\n" - # Check for completion signal in raw log and text log - if grep -q "COMPLETE" "$RAW_LOG" 2>/dev/null || \ - grep -q "COMPLETE" "$TEXT_LOG" 2>/dev/null; then + # Check for completion signal in text log ONLY (not raw log — raw log contains + # the CLAUDE.md prompt which has the literal COMPLETE instruction) + if grep -q "COMPLETE" "$TEXT_LOG" 2>/dev/null; then echo "" printf "\033[0;32mRalph completed all tasks!\033[0m\n" echo "Completed at iteration $i of $MAX_ITERATIONS"