Skip to content

fix: restore YouTube typing intro in demo route#214

Merged
ComBba merged 5 commits intomainfrom
fix/demo-youtube-typing-intro
Mar 18, 2026
Merged

fix: restore YouTube typing intro in demo route#214
ComBba merged 5 commits intomainfrom
fix/demo-youtube-typing-intro

Conversation

@ComBba
Copy link
Contributor

@ComBba ComBba commented Mar 18, 2026

Summary

  • restore the /demo landing autoplay so it starts by focusing the YouTube input and typing the demo URL before clicking Start
  • keep the fix scoped to web/src/app/demo/page.tsx, leaving the shared landing component unchanged
  • guard startSession() so the landing timer and dashboard fallback cannot double-start the same demo session

Verification

  • npx eslint src/app/demo/page.tsx
  • NEXT_PUBLIC_AGENT_URL=http://localhost:8080 npm run build

Notes

  • This restores the behavior introduced in 23dc552 and lost during the landing-sharing refactor in 09de86f
  • Oracle review confirmed the choreography is sound and specifically recommended the duplicate-start guard included here

Summary by CodeRabbit

  • 데모 경험 개선

    • 데모 입력/클릭 애니메이션, 타이밍 상수 및 대시보드 전환이 정교화되었습니다.
    • 자동 데모 시퀀스에서 중복 세션 시작을 방지하는 보호 로직이 추가되어 안정성이 향상되었습니다.
  • 테스트 및 API 대응

    • 시작 API에 대한 테스트가 SSE 스트림 대신 JSON 응답 검증으로 전환되었습니다.
    • 일부 액션/오류 시나리오 검증이 갱신되어 에러 응답 처리와 허용 상태 코드 범위가 반영되었습니다.

@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request reintroduces an interactive animation to the demo landing page, enhancing the user experience by visually simulating the input of a YouTube URL before initiating a demo session. It also improves the robustness of session management by preventing unintended multiple session starts, ensuring a smoother and more controlled demo flow.

Highlights

  • Restore YouTube Typing Intro: The /demo landing page now features the autoplay sequence where the YouTube input is focused, the demo URL is typed out, and the 'Start' button is clicked, restoring previous behavior.
  • Scoped Fix: The changes are specifically applied to web/src/app/demo/page.tsx, ensuring the shared landing component remains untouched.
  • Duplicate Session Start Guard: A mechanism has been implemented to prevent startSession() from being called multiple times, addressing potential double-starts from the landing timer and dashboard fallback.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea0b9944-531a-4741-a2b2-c3ccc4186989

📥 Commits

Reviewing files that changed from the base of the PR and between 06f4a94 and e523c6f.

📒 Files selected for processing (1)
  • agent/tests/test_zp_routes.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • agent/tests/test_zp_routes.py

Walkthrough

데모 자동화 랜딩 시퀀스를 재작성해 클릭·타이핑·버튼 상호작용을 타이밍 상수로 제어하고, 중복 startSession 호출을 막기 위해 sessionStartedRef를 도입했습니다. 테스트들은 SSE 파싱에서 JSON 응답 검증으로 전환되었습니다.

변경 사항

Cohort / File(s) Summary
데모 자동화 시퀀싱
web/src/app/demo/page.tsx
DEMO_* 타이밍 상수 추가. youtubeUrl 초깃값을 빈 문자열로 변경. 랜딩 시퀀스 재작성: 입력 클릭 애니메이션, 문자별 타이핑, 버튼 클릭 및 대시보드 전환 지연을 타이밍 기반으로 구현하고 sessionStartedRef로 중복 startSession 실행 방지.
테스트: SSE → JSON 전환
agent/tests/test_zp_routes.py
SSE 이벤트 파싱 제거 및 테스트가 resp.json() 기반 검증으로 변경. 세션 시작 테스트 이름/기대값을 SSE 스트림에서 JSON 세션 응답(session_id, goal_go_cards, status)으로 업데이트. 액션 테스트 페이로드/응답(예: queue_build 오류 처리, 허용되는 HTTP 상태 변경)도 수정됨.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser as Browser (Demo Page)
  participant Demo as Demo Component
  participant API as StartSession API
  participant Server as Server
  participant UI as Dashboard

  Browser->>Demo: 랜딩 시퀀스 트리거 (커서 이동)
  Demo->>Demo: 입력 클릭 애니메이션 (DEMO_INPUT_CLICK_*)
  Demo->>Demo: 문자별 타이핑 (DEMO_INPUT_TYPE_DELAY_MS ...)
  Demo->>Demo: 버튼으로 커서 이동 및 클릭 (DEMO_START_BTN_*)
  Demo->>API: startSession 요청 (검사: sessionStartedRef)
  API->>Server: 세션 생성 요청
  Server-->>API: JSON 응답 (session_id, goal_go_cards, status)
  API-->>Demo: JSON 전달
  Demo->>UI: 지연 후 대시보드 전환 (DEMO_SESSION_START_DELAY_MS ...)
  UI-->>Browser: 대시보드 렌더링
Loading

예상 코드 리뷰 노력

🎯 3 (Moderate) | ⏱️ ~20 분

관련 가능성 있는 PR

🐰 데모 춤을 추며
커서가 살며시 건네고,
글자들이 하나씩 노래하네,
클릭은 단 한 번, 세션은 굳건히,
대시보드로 훌쩍! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 주요 변경 사항을 명확하게 요약합니다. 데모 라우트에서 YouTube 타이핑 인트로를 복구하는 것이 핵심 변경 사항이며, raw_summary의 파일 변경 사항과 pr_objectives와 일치합니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/demo-youtube-typing-intro
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request restores the typing animation for the YouTube URL on the demo page and adds a guard to prevent the demo session from starting twice. The changes are well-implemented, using constants for animation timings and a useRef for the session start guard. I have one suggestion to further improve maintainability by extracting the few remaining magic numbers for animation delays into constants.

Comment on lines +88 to +110
queueTimer(() => moveCursorToElement(introInputRef.current), 600);
queueTimer(() => setCursor((prev) => ({ ...prev, clicking: true })), DEMO_INPUT_CLICK_DELAY_MS);
queueTimer(() => setCursor((prev) => ({ ...prev, clicking: false })), 1120);

DEMO_VIDEO_URL.split("").forEach((_, index) => {
queueTimer(() => {
setYoutubeUrl(DEMO_VIDEO_URL.slice(0, index + 1));
}, DEMO_INPUT_TYPING_START_MS + index * DEMO_INPUT_TYPING_STEP_MS);
});

const typingCompleteAt = DEMO_INPUT_TYPING_START_MS + DEMO_VIDEO_URL.length * DEMO_INPUT_TYPING_STEP_MS;

queueTimer(() => moveCursorToElement(zeroPromptStartRef.current), typingCompleteAt + DEMO_START_BUTTON_MOVE_DELAY_MS);
queueTimer(() => setCursor((prev) => ({ ...prev, clicking: true })), typingCompleteAt + DEMO_START_BUTTON_CLICK_DELAY_MS);
queueTimer(() => setCursor((prev) => ({ ...prev, clicking: false })), typingCompleteAt + 1240);
queueTimer(() => {
if (sessionStartedRef.current) return;
sessionStartedRef.current = true;
startSession();
}, 1250);
}, typingCompleteAt + DEMO_SESSION_START_DELAY_MS);
queueTimer(() => {
setStage("dashboard");
}, 2150);
}, typingCompleteAt + DEMO_SESSION_START_DELAY_MS + 900);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While many animation timings have been extracted to constants, several magic numbers remain. To improve consistency and maintainability, these should also be defined as constants. Specifically:

  • 600 on line 88
  • 1120 on line 90
  • 1240 on line 102
  • 900 on line 110

You could define new constants like DEMO_CURSOR_MOVE_TO_INPUT_DELAY_MS, DEMO_INPUT_CLICK_END_MS, etc., at the top of the file and use them here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
web/src/app/demo/page.tsx (1)

90-90: 매직 넘버를 상수로 추출하는 것을 권장합니다.

Lines 90, 102, 110에 하드코딩된 지연 시간(1120, 1240, 900)이 16-21번 라인에서 정의한 상수 패턴과 일관되지 않습니다. 유지보수성을 위해 상수로 추출하는 것이 좋습니다.

♻️ 상수 추출 제안
 const DEMO_INPUT_CLICK_DELAY_MS = 900;
 const DEMO_INPUT_TYPING_START_MS = 1300;
 const DEMO_INPUT_TYPING_STEP_MS = 32;
 const DEMO_START_BUTTON_MOVE_DELAY_MS = 700;
 const DEMO_START_BUTTON_CLICK_DELAY_MS = 1050;
 const DEMO_SESSION_START_DELAY_MS = 1360;
+const DEMO_INPUT_CLICK_RELEASE_MS = 1120;
+const DEMO_START_BUTTON_RELEASE_MS = 1240;
+const DEMO_DASHBOARD_TRANSITION_DELAY_MS = 900;
-    queueTimer(() => setCursor((prev) => ({ ...prev, clicking: false })), 1120);
+    queueTimer(() => setCursor((prev) => ({ ...prev, clicking: false })), DEMO_INPUT_CLICK_RELEASE_MS);
-    queueTimer(() => setCursor((prev) => ({ ...prev, clicking: false })), typingCompleteAt + 1240);
+    queueTimer(() => setCursor((prev) => ({ ...prev, clicking: false })), typingCompleteAt + DEMO_START_BUTTON_RELEASE_MS);
-    }, typingCompleteAt + DEMO_SESSION_START_DELAY_MS + 900);
+    }, typingCompleteAt + DEMO_SESSION_START_DELAY_MS + DEMO_DASHBOARD_TRANSITION_DELAY_MS);

Also applies to: 102-102, 108-110

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/app/demo/page.tsx` at line 90, Hardcoded delay values (1120, 1240,
900) used in calls like queueTimer(() => setCursor(...)) should be extracted
into named constants to match the pattern at the top of the file; define clear
constants (e.g., CURSOR_CLICK_DELAY, CURSOR_HELD_DELAY, CURSOR_RELEASE_DELAY)
near the other constants and replace the literal numbers in calls to queueTimer
and any other uses (references: queueTimer, setCursor, and the cursor state
updates) so the file is consistent and easier to maintain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/src/app/demo/page.tsx`:
- Line 90: Hardcoded delay values (1120, 1240, 900) used in calls like
queueTimer(() => setCursor(...)) should be extracted into named constants to
match the pattern at the top of the file; define clear constants (e.g.,
CURSOR_CLICK_DELAY, CURSOR_HELD_DELAY, CURSOR_RELEASE_DELAY) near the other
constants and replace the literal numbers in calls to queueTimer and any other
uses (references: queueTimer, setCursor, and the cursor state updates) so the
file is consistent and easier to maintain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 56eb6ea9-7d9b-4169-af55-cdc45e42f492

📥 Commits

Reviewing files that changed from the base of the PR and between 756f74e and 3c0ad5f.

📒 Files selected for processing (1)
  • web/src/app/demo/page.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
agent/server.py (1)

1151-1168: 중복된 일시정지 로직을 헬퍼 함수로 추출 권장.

Lines 1151-1168과 Lines 1217-1234의 일시정지 로직이 거의 동일합니다. 이 패턴을 헬퍼 함수로 추출하면 유지보수성이 향상됩니다.

♻️ 리팩토링 제안
+async def _pause_session_on_rejection_cap(session, session_id: str) -> None:
+    """Pause session when rejection cap is reached and emit event."""
+    session.status = "paused"
+    logger.info("[ZP] Rejected cap reached (10 cards) for session %s", session_id)
+    try:
+        from .db import zp_store as _zps
+        await _zps.update_session(session_id, status="paused")
+    except Exception:
+        logger.exception("[ZP] Failed to persist paused status for %s", session_id)
+    push_zp_event(
+        {
+            "type": "zp.session.pause",
+            "reason": "rejected_cap_reached",
+            "rejected_cards": _count_rejected_cards(session),
+            "session_id": session_id,
+        }
+    )

그런 다음 두 위치에서 이 헬퍼를 호출:

if session and _count_rejected_cards(session) >= 10:
    await _pause_session_on_rejection_cap(session, session_id)
    break

Also applies to: 1217-1234

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent/server.py` around lines 1151 - 1168, Extract the duplicated pause logic
into a helper async function (e.g. _pause_session_on_rejection_cap(session,
session_id)) that performs the check/update/push: set session.status = "paused",
log with logger.info, call zp_store.update_session (await
_zps.update_session(session_id, status="paused")) inside a try/except and
logger.exception on failure, call push_zp_event with the same payload (type
"zp.session.pause", reason "rejected_cap_reached", rejected_cards from
_count_rejected_cards(session), and session_id), and return when done; then
replace both original blocks (the ones using _count_rejected_cards(session) >=
10) with a single call to await _pause_session_on_rejection_cap(session,
session_id) followed by break so behavior and error handling remain identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@agent/server.py`:
- Around line 1160-1167: The frontend is missing a handler for the backend event
type "zp.session.pause" in the formatEventMessage function, so include a new
case for "zp.session.pause" that extracts the event.payload.reason and
event.payload.rejected_cards and returns a user-facing message (or structured
object) showing the pause reason and the number of rejected cards; update any
switch/case or mapping in formatEventMessage to handle "zp.session.pause" and
ensure the UI consumer of formatEventMessage uses the returned text/fields to
display the pause reason and rejected_cards count.

---

Nitpick comments:
In `@agent/server.py`:
- Around line 1151-1168: Extract the duplicated pause logic into a helper async
function (e.g. _pause_session_on_rejection_cap(session, session_id)) that
performs the check/update/push: set session.status = "paused", log with
logger.info, call zp_store.update_session (await _zps.update_session(session_id,
status="paused")) inside a try/except and logger.exception on failure, call
push_zp_event with the same payload (type "zp.session.pause", reason
"rejected_cap_reached", rejected_cards from _count_rejected_cards(session), and
session_id), and return when done; then replace both original blocks (the ones
using _count_rejected_cards(session) >= 10) with a single call to await
_pause_session_on_rejection_cap(session, session_id) followed by break so
behavior and error handling remain identical.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 34f46541-8ee8-47c9-8754-3f4f24801388

📥 Commits

Reviewing files that changed from the base of the PR and between 3c0ad5f and 40589d2.

📒 Files selected for processing (5)
  • agent/server.py
  • agent/zero_prompt/competitive_analysis.py
  • agent/zero_prompt/insight_extractor.py
  • agent/zero_prompt/orchestrator.py
  • web/src/app/demo/page.tsx

Comment on lines +1160 to +1167
push_zp_event(
{
"type": "zp.session.pause",
"reason": "rejected_cap_reached",
"rejected_cards": _count_rejected_cards(session),
"session_id": session_id,
}
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: 프론트엔드에서 pause 이벤트 처리 여부 확인
rg -n "session.pause\|zp\.session\.pause\|pause" web/src/hooks/use-zero-prompt.ts

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 51


🏁 Script executed:

# 파일 존재 여부와 기본 정보 확인
fd -t f "use-zero-prompt" web/

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 101


🏁 Script executed:

# 파일 크기와 전체 구조 확인
wc -l web/src/hooks/use-zero-prompt.ts 2>/dev/null || echo "파일을 찾을 수 없습니다"

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 105


🏁 Script executed:

# formatEventMessage 함수와 이벤트 핸들러 찾기
rg -A 50 "formatEventMessage" web/src/hooks/ --type ts

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 9122


🏁 Script executed:

# agent/server.py에서 zp.session.pause 이벤트 전송 확인
rg -B 5 -A 2 "zp.session.pause" agent/server.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 987


🏁 Script executed:

# 혹시 다른 곳에서 pause 이벤트를 처리하는지 확인
rg -i "zp.session.pause" web/ --type ts

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 51


zp.session.pause 이벤트에 대한 프론트엔드 핸들러 추가 필요

formatEventMessage 함수에 zp.session.pause 이벤트 타입이 누락되었습니다. 백엔드에서 세션 일시정지 시 reason과 rejected_cards 데이터를 포함하여 이벤트를 전송하지만, 프론트엔드에서는 이 정보를 사용자에게 표시할 수 없습니다. 대시보드는 자동으로 새로고침되지만 일시정지 사유와 거부된 카드 개수 정보가 UI에 표시되지 않아 사용자 경험에 영향을 줍니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent/server.py` around lines 1160 - 1167, The frontend is missing a handler
for the backend event type "zp.session.pause" in the formatEventMessage
function, so include a new case for "zp.session.pause" that extracts the
event.payload.reason and event.payload.rejected_cards and returns a user-facing
message (or structured object) showing the pause reason and the number of
rejected cards; update any switch/case or mapping in formatEventMessage to
handle "zp.session.pause" and ensure the UI consumer of formatEventMessage uses
the returned text/fields to display the pause reason and rejected_cards count.

@ComBba ComBba force-pushed the fix/demo-youtube-typing-intro branch from 40589d2 to a951711 Compare March 18, 2026 18:40
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
web/src/app/demo/page.tsx (1)

95-99: 타이핑 애니메이션 구현 - 간결하고 효과적입니다.

split("").forEach를 사용한 문자별 타이핑 효과가 잘 구현되어 있습니다. 다만 한 가지 고려사항이 있습니다:

URL에 이모지나 서로게이트 페어(surrogate pair) 문자가 포함될 경우 split("")은 예상과 다르게 동작할 수 있습니다. 현재 DEMO_VIDEO_URL은 ASCII 문자만 포함하므로 문제없지만, 향후 URL 변경 시 주의가 필요합니다.

🔧 유니코드 안전한 구현 (선택적)
-    DEMO_VIDEO_URL.split("").forEach((_, index) => {
+    [...DEMO_VIDEO_URL].forEach((_, index) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/app/demo/page.tsx` around lines 95 - 99, The current per-character
typing loop uses DEMO_VIDEO_URL.split("") which can break on surrogate
pairs/emoji; make the iteration Unicode-safe by iterating over
Array.from(DEMO_VIDEO_URL) (or [...DEMO_VIDEO_URL]) instead of split(""),
keeping the same queueTimer callback that calls
setYoutubeUrl(DEMO_VIDEO_URL.slice(0, index + 1)) and the existing timing
constants DEMO_INPUT_TYPING_START_MS and DEMO_INPUT_TYPING_STEP_MS so the typing
animation behaves correctly for multi-code-unit characters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/src/app/demo/page.tsx`:
- Around line 95-99: The current per-character typing loop uses
DEMO_VIDEO_URL.split("") which can break on surrogate pairs/emoji; make the
iteration Unicode-safe by iterating over Array.from(DEMO_VIDEO_URL) (or
[...DEMO_VIDEO_URL]) instead of split(""), keeping the same queueTimer callback
that calls setYoutubeUrl(DEMO_VIDEO_URL.slice(0, index + 1)) and the existing
timing constants DEMO_INPUT_TYPING_START_MS and DEMO_INPUT_TYPING_STEP_MS so the
typing animation behaves correctly for multi-code-unit characters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 24a39727-6b5e-4d83-847a-ff9fc9c5f079

📥 Commits

Reviewing files that changed from the base of the PR and between 40589d2 and a951711.

📒 Files selected for processing (1)
  • web/src/app/demo/page.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
agent/tests/test_zp_routes.py (1)

18-20: /api 프리픽스 경로도 동일한 응답 계약 필드를 검증해 주세요.

현재는 session_id만 확인해서 goal_go_cards, status 회귀를 놓칠 수 있습니다.

제안 diff
 async def test_zp_start_api_prefix(app_client):
     resp = await app_client.post("/api/zero-prompt/start", json={})
     assert resp.status_code == 200
     body = resp.json()
     assert body["session_id"]
+    assert body["goal_go_cards"] == 5
+    assert body["status"] == "exploring"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent/tests/test_zp_routes.py` around lines 18 - 20, 현재 테스트 only asserts
body["session_id"] for the response deserialized into resp -> body; extend the
assertions to also validate the presence (and basic types/contents if
appropriate) of the other contract fields "goal_go_cards" and "status" for the
`/api`-prefixed route responses so regressions are caught; update the test that
calls resp.json() (where body is assigned) to include assertions for
body["goal_go_cards"] and body["status"] alongside the existing assert
body["session_id"].
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@agent/tests/test_zp_routes.py`:
- Around line 51-55: The test is asserting a 500 for a missing card which hides
that the handler lacks input validation; update the force_go route handler to
explicitly verify the card exists (e.g., call get_card or the repository method
used elsewhere) before calling update_card or session.build_queue.remove, and
return a 4xx error (404 Not Found or 400 Bad Request) with a clear message when
the card_id is missing; then update the test in agent/tests/test_zp_routes.py to
call the same endpoint with "missing-card" and assert the 4xx status and the
expected error detail instead of expecting 500/Internal Server Error.

---

Nitpick comments:
In `@agent/tests/test_zp_routes.py`:
- Around line 18-20: 현재 테스트 only asserts body["session_id"] for the response
deserialized into resp -> body; extend the assertions to also validate the
presence (and basic types/contents if appropriate) of the other contract fields
"goal_go_cards" and "status" for the `/api`-prefixed route responses so
regressions are caught; update the test that calls resp.json() (where body is
assigned) to include assertions for body["goal_go_cards"] and body["status"]
alongside the existing assert body["session_id"].
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5f0496b0-a003-48d8-8a87-94b8af1c8b7c

📥 Commits

Reviewing files that changed from the base of the PR and between a951711 and 06f4a94.

📒 Files selected for processing (1)
  • agent/tests/test_zp_routes.py

Comment on lines +51 to +55
json={"action": "force_go", "card_id": "missing-card"},
)
assert resp.status_code == 200
assert resp.status_code == 500
body = resp.json()
assert body["type"] == "zp.action.pause"
assert body["detail"] == "Internal Server Error"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) action 핸들러에서 force_go 분기/예외 매핑 확인
rg -nC3 'elif action == "force_go"|HTTPException\(status_code=422|unknown_action|return result' agent/server.py

# 2) DB update_card가 미존재 카드/잘못된 ID를 어떻게 처리하는지 확인
rg -nC3 'async def update_card|UPDATE zp_cards SET|WHERE id' agent/db/zp_store.py

# 3) zp_cards.id 타입 정의 확인(500 원인 추정: uuid 캐스팅 실패 여부)
rg -nC2 'CREATE TABLE\s+zp_cards|id\s+(uuid|text|varchar)' -g '*.sql' -g '*.py'

# 4) 현재 테스트의 500 기대 위치 재확인
rg -nC2 'test_zp_action_queue_build|force_go|Internal Server Error|status_code == 500' agent/tests/test_zp_routes.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 4262


🏁 Script executed:

# force_go 핸들러 전체 블록 추출 (더 많은 라인)
sed -n '1325,1360p' agent/server.py

# 또한 result 변수가 force_go에서 초기화되는지 확인
rg -n 'elif action == "force_go"' -A 20 agent/server.py | head -30

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 2821


🏁 Script executed:

# 카드 ID 유효성 검사 또는 UUID 캐스팅 여부 확인
rg -n 'card_id|uuid|UUID' agent/server.py | grep -i 'force_go\|update_card\|parse\|valid' | head -10

# DB 테이블 스키마 확인 (zp_cards.id 타입)
find . -name '*.sql' -o -name '*migration*' -o -name '*schema*' | xargs grep -l 'zp_cards' 2>/dev/null || echo "No SQL files found"

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 648


🏁 Script executed:

cat agent/db/schema.sql

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 4879


🏁 Script executed:

# 또한 ensure_session 메서드와 오케스트레이터 확인
rg -n 'def ensure_session|async def ensure_session' -A 10 agent/

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 1622


🏁 Script executed:

# update_card 함수에서 어떤 예외가 발생할 수 있는지 확인
rg -n 'async def update_card' -A 20 agent/db/zp_store.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 827


🏁 Script executed:

rg -n 'class ZPSession' -A 20 agent/

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 671


🏁 Script executed:

# session.cards가 None일 가능성 확인
rg -n 'self.cards' agent/zero_prompt/orchestrator.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 51


🏁 Script executed:

# 테스트 설정 확인 - session이 생성될 때 cards 초기화 방식
sed -n '45,56p' agent/tests/test_zp_routes.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 490


🏁 Script executed:

# /zero-prompt/{session_id}/actions 엔드포인트 정의 찾기
rg -n '@app.post.*zero-prompt.*actions|def.*actions' -A 5 agent/server.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 408


🏁 Script executed:

# push_zp_event 함수 확인
rg -n 'def push_zp_event|async def push_zp_event' -A 10 agent/server.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 51


🏁 Script executed:

# 전체 엔드포인트 함수 정의 (request 파라미터와 검증)
sed -n '1290,1365p' agent/server.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 3496


🏁 Script executed:

# push_zp_event 함수 전체 구현 찾기
rg -n 'push_zp_event' -B 2 -A 15 agent/server.py | head -50

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 2101


🏁 Script executed:

# ZPActionRequest 데이터 타입 정의 확인 (입력 검증)
rg -n 'class ZPActionRequest' -A 10 agent/

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 535


🏁 Script executed:

# 테스트를 실행했을 때 실제로 500이 발생하는지 확인
# 또는 테스트 파일에 더 많은 관련 테스트가 있는지 확인
grep -n 'force_go\|missing-card\|500\|Internal Server' agent/tests/test_zp_routes.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 229


🏁 Script executed:

# push_zp_event 함수 정의 찾기 (event_bus 파일)
find agent -name 'event_bus.py' -exec cat {} \;

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 947


🏁 Script executed:

# 테스트 전체 맥락 확인 - fixture 설정 등
head -60 agent/tests/test_zp_routes.py

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 1850


🏁 Script executed:

# 혹시 다른 force_go 관련 테스트나 exception 핸들링이 있는지 확인
rg -n 'force_go|zp_action_queue_build' agent/tests/

Repository: Two-Weeks-Team/vibeDeploy

Length of output: 248


카드 존재 여부를 검증하지 않아 핸들러 오류를 테스트로 고착하고 있습니다.

missing-card처럼 존재하지 않는 카드 ID로 force_go를 호출하면 현재:

  1. update_card()는 경합 없이 종료 (0행 업데이트)
  2. session.build_queue.remove(card_id) 호출 전 확인되지만, 카드 검증 자체는 없음
  3. 핸들러가 성공 응답 반환

테스트가 500 + "Internal Server Error"를 기대하는 것은 이 동작을 고착시키고 있습니다. 대신 명시적 입력 검증을 추가하고 적절한 4xx 상태로 응답해야 합니다.

제안 수정
     resp = await app_client.post(
         f"/zero-prompt/{session_id}/actions",
         json={"action": "force_go", "card_id": "missing-card"},
     )
-    assert resp.status_code == 500
+    assert resp.status_code == 422
     body = resp.json()
-    assert body["detail"] == "Internal Server Error"
+    assert "detail" in body
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent/tests/test_zp_routes.py` around lines 51 - 55, The test is asserting a
500 for a missing card which hides that the handler lacks input validation;
update the force_go route handler to explicitly verify the card exists (e.g.,
call get_card or the repository method used elsewhere) before calling
update_card or session.build_queue.remove, and return a 4xx error (404 Not Found
or 400 Bad Request) with a clear message when the card_id is missing; then
update the test in agent/tests/test_zp_routes.py to call the same endpoint with
"missing-card" and assert the 4xx status and the expected error detail instead
of expecting 500/Internal Server Error.

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

⚠️ Branch updated during autofix.

The branch was updated while autofix was in progress. Please try again.

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

⚠️ Branch updated during autofix.

The branch was updated while autofix was in progress. Please try again.

@ComBba ComBba merged commit 06f3629 into main Mar 18, 2026
9 checks passed
@ComBba ComBba deleted the fix/demo-youtube-typing-intro branch March 18, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant