fix: update CP immediately after predicting#4504
Conversation
📝 WalkthroughWalkthroughForecasterQuestionView and ForecastMaker now use local post state and a wrapped onPredictionSubmit that refetches the post via ClientPostsApi.getPost before delegating, ensuring sibling components render updated community predictions immediately after a submit. ChangesRefetch-on-submit cohort
Sequence DiagramsequenceDiagram
participant User
participant ForecastMaker
participant ForecasterQuestionView
participant ClientPostsApi
participant SiblingComponents
User->>ForecastMaker: Click Predict / Submit
ForecastMaker->>ForecasterQuestionView: invoke onPredictionSubmit (handlePredictionSubmit)
ForecasterQuestionView->>ClientPostsApi: getPost(postId)
activate ClientPostsApi
ClientPostsApi-->>ForecasterQuestionView: return fresh post
deactivate ClientPostsApi
ForecasterQuestionView->>ForecasterQuestionView: set currentPost
ForecasterQuestionView->>ForecastMaker: (call original onPredictionSubmit/continue)
ForecasterQuestionView->>SiblingComponents: render updated post (CP updated)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Cleanup: Preview Environment RemovedThe preview environment for this PR has been destroyed.
Cleanup triggered by PR close at 2026-05-19T15:21:41Z |
|
Seems I can't test this because the preview env doesn't recompute CP at all? |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
front_end/src/components/forecast_maker/index.tsx (1)
35-37: Add minimal error telemetry for CP refresh failures.Line 35-37 silently swallows refresh errors, which makes production debugging hard when CP does not update as expected.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front_end/src/components/forecast_maker/index.tsx` around lines 35 - 37, The empty catch in the forecast_maker component swallows CP refresh errors; change the anonymous catch to capture the error (catch (err)) and emit minimal telemetry and/or log the error so failures are visible in production (e.g., call your telemetry helper like sendTelemetry or trackError with an event name such as "CPRefreshFailed" and include err.message/stack), then keep the existing comment/behavior if desired; update the catch in front_end/src/components/forecast_maker/index.tsx accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@front_end/src/components/forecast_maker/index.tsx`:
- Around line 31-35: The async fetch in handlePredictionSubmit uses
currentPost.id then unconditionally calls setCurrentPost with the response,
which lets a stale response overwrite newer state; fix by capturing the
request's intended id (e.g., const requestedId = currentPost.id) before awaiting
ClientPostsApi.getPost(requestedId) and, after the await, verify the component
still intends to update that same id (compare requestedId to the latest
currentPost.id or an up-to-date ref) before calling setCurrentPost;
alternatively cancel/ignore responses with an AbortController or mounted flag so
setCurrentPost only runs for the latest in-flight request.
---
Nitpick comments:
In `@front_end/src/components/forecast_maker/index.tsx`:
- Around line 35-37: The empty catch in the forecast_maker component swallows CP
refresh errors; change the anonymous catch to capture the error (catch (err))
and emit minimal telemetry and/or log the error so failures are visible in
production (e.g., call your telemetry helper like sendTelemetry or trackError
with an event name such as "CPRefreshFailed" and include err.message/stack),
then keep the existing comment/behavior if desired; update the catch in
front_end/src/components/forecast_maker/index.tsx accordingly.
🪄 Autofix (Beta)
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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f489c6e1-eb20-45be-88a3-6528357d669b
📒 Files selected for processing (1)
front_end/src/components/forecast_maker/index.tsx
| const { | ||
| group_of_questions: groupOfQuestions, | ||
| conditional, | ||
| question, | ||
| } = currentPost; |
There was a problem hiding this comment.
Fresh post only threads into ForecastMaker subtree. Sibling DetailedQuestionCard / DetailedGroupCard in forecaster_question_view still render stale CP from parent postData until revalidatePath lands. If #4437 is about the chart, this won't fix it – lift the refetch to the parent page.
| try { | ||
| const freshPost = await ClientPostsApi.getPost(currentPost.id); | ||
| setCurrentPost(freshPost); |
There was a problem hiding this comment.
Double-fetch in prediction flow: prediction_flow_post.tsx:62 already refetches the post in its own onPredictionSubmit. This wrapper now fires a second GET /posts/:id right before it.
| useEffect(() => { | ||
| setCurrentPost(post); | ||
| }, [post]); |
There was a problem hiding this comment.
Race: local setCurrentPost(fresh) can be overwritten moments later when the parent re-renders with a staler post prop from revalidatePath, via the useEffect sync. Causes a flash back to stale CP.
|
@claude please make requested changes. |
|
Claude finished @SylvainChevalier's task in 7m 49s —— View job Changes pushed ✓Addressed all three review points from @ncarazon and the stale-response concern from @coderabbitai by lifting the post refetch out of Why this is the right shape
Concerns addressed
Files changed
Tasks
Notes
Commit: |
Move the post-prediction refetch out of ForecastMaker and into the parent ForecasterQuestionView so that siblings (DetailedQuestionCard / DetailedGroupCard) also render the fresh CP immediately, not just the forecast maker subtree. Also avoids double-fetching in the prediction flow, where prediction_flow_post already refetches on submit, and protects against stale in-flight responses via a request-id ref. Addresses review feedback from @ncarazon and @coderabbitai on #4504. Co-authored-by: Sylvain <SylvainChevalier@users.noreply.github.com>
|
@claude resolve the conflicts please. |
|
Claude finished @SylvainChevalier's task in 4m 22s —— View job Blocked — can't fetch latest
|
After submitting a prediction, fetch fresh post data (including updated CP) from the API, matching the reaffirm flow pattern. Previously, the predict flow relied solely on revalidatePath which didn't reliably update the client-side CP display. Closes #4437 Co-authored-by: Sylvain <SylvainChevalier@users.noreply.github.com>
Move the post-prediction refetch out of ForecastMaker and into the parent ForecasterQuestionView so that siblings (DetailedQuestionCard / DetailedGroupCard) also render the fresh CP immediately, not just the forecast maker subtree. Also avoids double-fetching in the prediction flow, where prediction_flow_post already refetches on submit, and protects against stale in-flight responses via a request-id ref. Addresses review feedback from @ncarazon and @coderabbitai on #4504. Co-authored-by: Sylvain <SylvainChevalier@users.noreply.github.com>
4bb0bb7 to
657f77b
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@front_end/src/app/`(main)/questions/[id]/components/question_view/forecaster_question_view/index.tsx:
- Around line 39-45: The async response can overwrite state for a different
question after navigation; before calling ClientPostsApi.getPost save the
current post id (e.g., const requestPostId = postData.id) and after the await
verify both that the response is not stale (requestId ===
latestRequestIdRef.current) and that the post id still matches (requestPostId
=== postData.id) before calling setCurrentPost; reference
handlePredictionSubmit, latestRequestIdRef, postData.id and setCurrentPost when
applying this guard.
🪄 Autofix (Beta)
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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ea454434-c023-4dd0-8467-39402c65a403
📒 Files selected for processing (1)
front_end/src/app/(main)/questions/[id]/components/question_view/forecaster_question_view/index.tsx
| const handlePredictionSubmit = useCallback(async () => { | ||
| const requestId = ++latestRequestIdRef.current; | ||
| try { | ||
| const freshPost = await ClientPostsApi.getPost(postData.id); | ||
| // Ignore stale responses if a newer request has been issued meanwhile. | ||
| if (requestId === latestRequestIdRef.current) { | ||
| setCurrentPost(freshPost); |
There was a problem hiding this comment.
Prevent stale async refresh from overwriting a different question after navigation.
requestId ordering alone is not enough across post-id changes. If a user navigates to another question before this resolves, this response can still set currentPost to the previous post.
Suggested fix
const ForecasterQuestionView: React.FC<Props> = ({
postData,
preselectedGroupQuestionId,
}) => {
const [currentPost, setCurrentPost] = useState(postData);
const latestRequestIdRef = useRef(0);
+ const activePostIdRef = useRef(postData.id);
// Sync local state when the server prop changes (e.g., after a
// revalidatePath-driven re-render).
useEffect(() => {
+ activePostIdRef.current = postData.id;
setCurrentPost(postData);
}, [postData]);
// Refetch fresh post data (including updated CP) after a prediction is
// submitted, so sibling components (DetailedQuestionCard /
// DetailedGroupCard) render the updated CP immediately instead of waiting
// for revalidatePath to land.
const handlePredictionSubmit = useCallback(async () => {
+ const requestedPostId = postData.id;
const requestId = ++latestRequestIdRef.current;
try {
- const freshPost = await ClientPostsApi.getPost(postData.id);
+ const freshPost = await ClientPostsApi.getPost(requestedPostId);
// Ignore stale responses if a newer request has been issued meanwhile.
- if (requestId === latestRequestIdRef.current) {
+ if (
+ requestId === latestRequestIdRef.current &&
+ requestedPostId === activePostIdRef.current
+ ) {
setCurrentPost(freshPost);
}
} catch (err) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@front_end/src/app/`(main)/questions/[id]/components/question_view/forecaster_question_view/index.tsx
around lines 39 - 45, The async response can overwrite state for a different
question after navigation; before calling ClientPostsApi.getPost save the
current post id (e.g., const requestPostId = postData.id) and after the await
verify both that the response is not stale (requestId ===
latestRequestIdRef.current) and that the post id still matches (requestPostId
=== postData.id) before calling setCurrentPost; reference
handlePredictionSubmit, latestRequestIdRef, postData.id and setCurrentPost when
applying this guard.
Closes #4437
Summary
Test plan
Generated with Claude Code
Summary by CodeRabbit