Skip to content

PM-4824: honor actual predecessor end dates in schedule editor#1712

Merged
jmgasper merged 2 commits intodevfrom
PM-4824
Apr 10, 2026
Merged

PM-4824: honor actual predecessor end dates in schedule editor#1712
jmgasper merged 2 commits intodevfrom
PM-4824

Conversation

@jmgasper
Copy link
Copy Markdown
Collaborator

@jmgasper jmgasper commented Apr 10, 2026

What was broken
The work app schedule editor recalculated successor phase start times from the predecessor's scheduled end date, so a two-round design challenge could keep the Submission phase anchored to the old Checkpoint Review schedule after autopilot closed checkpoint review early. That made the Submission end-date picker reject earlier valid dates.

Root cause
The ChallengeScheduleSection recalculation helper ignored predecessor actual end dates during hydration and subsequent row recalculation, overwriting the shifted schedule returned by the backend.

What was changed
Updated the schedule recalculation helper to use a completed predecessor phase's actual end date when deriving successor phase start times.
Added targeted schedule tests covering the checkpoint review to submission transition.
Updated the ChallengeEditorPage schedule documentation to reflect the completed-predecessor behavior.

Any added/updated tests
Added unit coverage in ChallengeScheduleSection.spec.ts for closed predecessors shifting successor start times.
Added component coverage in ChallengeScheduleSection.component.spec.tsx for the submission row start date after an early checkpoint review close.
Ran yarn lint and yarn run build successfully.
Ran yarn test:no-watch --runTestsByPath for the updated schedule tests successfully.
Ran yarn test:no-watch for the full suite; it still fails in the pre-existing wallet-admin PaymentsListView spec expectations around default filter values, unrelated to this schedule change.


Open with Devin

What was broken
Completed challenge phases in the work app schedule editor still exposed editable end date and duration controls, unlike legacy work-manager.

Root cause
Challenge phase normalization dropped `actualEndDate`, so the form lost the completion signal used by the legacy `canChangeDuration` rule and the schedule rows never disabled completed phases.

What was changed
Preserved phase completion timestamps when hydrating challenge editor form data.
Applied the legacy completed-phase editability rule to schedule row end date and duration controls while keeping the existing start-date rules intact.
Updated the challenge editor README to note the restored legacy behavior.

Any added/updated tests
Added a challenge-editor utils test that keeps `actualEndDate` in form state.
Added a schedule section test that verifies completed phases lock end date and duration controls.
What was broken
The work app schedule editor recalculated successor phase start times from the predecessor's scheduled end date, so a two-round design challenge could keep the Submission phase anchored to the old Checkpoint Review schedule after autopilot closed checkpoint review early. That made the Submission end-date picker reject earlier valid dates.

Root cause
The ChallengeScheduleSection recalculation helper ignored predecessor actual end dates during hydration and subsequent row recalculation, overwriting the shifted schedule returned by the backend.

What was changed
Updated the schedule recalculation helper to use a completed predecessor phase's actual end date when deriving successor phase start times.
Added targeted schedule tests covering the checkpoint review to submission transition.
Updated the ChallengeEditorPage schedule documentation to reflect the completed-predecessor behavior.

Any added/updated tests
Added unit coverage in ChallengeScheduleSection.spec.ts for closed predecessors shifting successor start times.
Added component coverage in ChallengeScheduleSection.component.spec.tsx for the submission row start date after an early checkpoint review close.
@jmgasper jmgasper requested a review from kkartunov as a code owner April 10, 2026 03:29
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +67 to +69
function getPredecessorEndDate(phase?: ChallengePhase): Date | undefined {
return toDate(phase?.actualEndDate || phase?.scheduledEndDate)
}
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.

🟡 getPredecessorEndDate applies || before parsing, losing scheduledEndDate fallback on invalid actualEndDate

The || in phase?.actualEndDate || phase?.scheduledEndDate operates on raw string values before date parsing. If actualEndDate is a truthy but unparseable string (e.g., malformed API data), the expression evaluates to that invalid string, toDate() returns undefined, and the valid scheduledEndDate is never tried. The correct pattern is toDate(phase?.actualEndDate) || toDate(phase?.scheduledEndDate) which tries parsing each value independently. This matters because actualEndDate is not validated through toIsoDateString during normalization (challenge-editor.utils.ts:858) unlike scheduledEndDate (challenge-editor.utils.ts:870), so invalid values could flow through undetected.

Suggested change
function getPredecessorEndDate(phase?: ChallengePhase): Date | undefined {
return toDate(phase?.actualEndDate || phase?.scheduledEndDate)
}
function getPredecessorEndDate(phase?: ChallengePhase): Date | undefined {
return toDate(phase?.actualEndDate) || toDate(phase?.scheduledEndDate)
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@jmgasper jmgasper merged commit cc4cd5f into dev Apr 10, 2026
9 checks passed
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