Skip to content

fix: update CP immediately after predicting#4504

Open
SylvainChevalier wants to merge 1 commit intomainfrom
claude/issue-4437-update-the-cp-on-predict
Open

fix: update CP immediately after predicting#4504
SylvainChevalier wants to merge 1 commit intomainfrom
claude/issue-4437-update-the-cp-on-predict

Conversation

@SylvainChevalier
Copy link
Copy Markdown
Contributor

@SylvainChevalier SylvainChevalier commented Mar 17, 2026

Closes #4437

Summary

  • 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

Test plan

  • Predict on a binary question and verify the CP updates immediately
  • Predict on a continuous question and verify the CP updates
  • Predict on a multiple choice question and verify the CP updates
  • Reaffirm a prediction and verify it still works correctly

Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • ForecastMaker now refreshes prediction data before submission, ensuring you're always working with the most current information when making predictions.

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>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

ForecastMaker component now maintains a local currentPost state synchronized with the incoming post prop. The onPredictionSubmit callback is wrapped to fetch the latest post data before delegating to the original handler, ensuring rendered state reflects current predictions immediately.

Changes

Cohort / File(s) Summary
ForecastMaker Local State & Callback Wrapping
front_end/src/components/forecast_maker/index.tsx
Added local currentPost state with useEffect sync, wrapped onPredictionSubmit to asynchronously fetch fresh post data via ClientPostsApi.getPost() before invoking original callback, and updated downstream component props to use currentPost.

Sequence Diagram

sequenceDiagram
    participant User
    participant ForecastMaker
    participant ClientPostsApi
    participant ChildComponents

    User->>ForecastMaker: Click Predict
    ForecastMaker->>ForecastMaker: handlePredictionSubmit triggered
    ForecastMaker->>ClientPostsApi: getPost(currentPost.id)
    activate ClientPostsApi
    ClientPostsApi-->>ForecastMaker: Fresh post data
    deactivate ClientPostsApi
    ForecastMaker->>ForecastMaker: Update currentPost state
    ForecastMaker->>ForecastMaker: Call original onPredictionSubmit
    ForecastMaker->>ChildComponents: Pass updated post & handlePredictionSubmit
    ChildComponents-->>User: Render with updated CP
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • feat: add pre-predictions #4557: Also modifies ForecastMaker component to compute and pass predictLabel, with overlapping changes to the same file requiring coordinated review.

Suggested reviewers

  • ncarazon
  • lsabor
  • hlbmtc

Poem

🐰 Predict, and see it bloom so bright,
Fresh numbers dancing in the light,
No waiting for a second click,
The CP updates—swift and quick!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: updating CP (Community Prediction) immediately after predicting, which directly addresses the PR's primary objective.
Linked Issues check ✅ Passed The code changes implement the core requirement from #4437 by fetching fresh post data with updated CP after prediction submission, mirroring the reaffirm flow pattern.
Out of Scope Changes check ✅ Passed All changes are scoped to ForecastMaker component's prediction handling, directly addressing the linked issue requirement with no unrelated modifications.

✏️ 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 claude/issue-4437-update-the-cp-on-predict
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch claude/issue-4437-update-the-cp-on-predict

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 17, 2026

🚀 Preview Environment

Your preview environment is ready!

Resource Details
🌐 Preview URL https://metaculus-pr-4504-claude-issue-4437-update-the-c-preview.mtcl.cc
📦 Docker Image ghcr.io/metaculus/metaculus:claude-issue-4437-update-the-cp-on-predict-021e1c6
🗄️ PostgreSQL NeonDB branch preview/pr-4504-claude-issue-4437-update-the-c
Redis Fly Redis mtc-redis-pr-4504-claude-issue-4437-update-the-c

Details

  • Commit: 021e1c6f072bdc42a2f78c66f5b3508de1578380
  • Branch: claude/issue-4437-update-the-cp-on-predict
  • Fly App: metaculus-pr-4504-claude-issue-4437-update-the-c

ℹ️ Preview Environment Info

Isolation:

  • PostgreSQL and Redis are fully isolated from production
  • Each PR gets its own database branch and Redis instance
  • Changes pushed to this PR will trigger a new deployment

Limitations:

  • Background workers and cron jobs are not deployed in preview environments
  • If you need to test background jobs, use Heroku staging environments

Cleanup:

  • This preview will be automatically destroyed when the PR is closed

@SylvainChevalier
Copy link
Copy Markdown
Contributor Author

Seems I can't test this because the preview env doesn't recompute CP at all?

@SylvainChevalier SylvainChevalier marked this pull request as ready for review April 7, 2026 21:30
Copy link
Copy Markdown
Contributor

@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)
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

📥 Commits

Reviewing files that changed from the base of the PR and between 8c53a55 and 021e1c6.

📒 Files selected for processing (1)
  • front_end/src/components/forecast_maker/index.tsx

Comment on lines +31 to +35
const handlePredictionSubmit = useCallback(async () => {
try {
const freshPost = await ClientPostsApi.getPost(currentPost.id);
setCurrentPost(freshPost);
} catch {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Protect setCurrentPost from stale async responses.

At Line 34, the fetched result is always applied. If the active post changes while this request is in flight, an older response can overwrite newer state.

Suggested fix
-  const handlePredictionSubmit = useCallback(async () => {
+  const handlePredictionSubmit = useCallback(async () => {
+    const submittedPostId = currentPost.id;
     try {
-      const freshPost = await ClientPostsApi.getPost(currentPost.id);
-      setCurrentPost(freshPost);
+      const freshPost = await ClientPostsApi.getPost(submittedPostId);
+      setCurrentPost((prev) =>
+        prev.id === submittedPostId ? freshPost : prev,
+      );
     } catch {
       // Silently fail - the CP will update on next page load
     }
     onPredictionSubmit?.();
   }, [currentPost.id, onPredictionSubmit]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handlePredictionSubmit = useCallback(async () => {
try {
const freshPost = await ClientPostsApi.getPost(currentPost.id);
setCurrentPost(freshPost);
} catch {
const handlePredictionSubmit = useCallback(async () => {
const submittedPostId = currentPost.id;
try {
const freshPost = await ClientPostsApi.getPost(submittedPostId);
setCurrentPost((prev) =>
prev.id === submittedPostId ? freshPost : prev,
);
} catch {
// Silently fail - the CP will update on next page load
}
onPredictionSubmit?.();
}, [currentPost.id, onPredictionSubmit]);
🤖 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 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.

Comment on lines +41 to +45
const {
group_of_questions: groupOfQuestions,
conditional,
question,
} = currentPost;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Comment on lines +32 to +34
try {
const freshPost = await ClientPostsApi.getPost(currentPost.id);
setCurrentPost(freshPost);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Comment on lines +25 to +27
useEffect(() => {
setCurrentPost(post);
}, [post]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

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.

Update the CP on predict

2 participants