LF-5381 Guard task selectors against plan entities missing from the s…#4252
Open
kathyavini wants to merge 1 commit into
Conversation
…tore Tasks and management plans arrive from independent fetches, and the tasks response embeds no planting management plans, so any tasks fetch that is not paired with a plans fetch stores tasks whose plan entities are absent; redux-persist then replays such snapshots across reloads. Make the task selector joins total over partial state: drop unresolvable plan references, skip tasks with no cached task type, and skip plant/transplant tasks whose planting management plan has not loaded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
World class AI vs
taskSlice.js😉I have not tested it yet and it is not urgent; the crashes in this sequence of actions (as in testing below) predated our last major release.
AI's description below:
Fixes a family of
TypeErrorcrashes in the task selectors that occur when the Redux store holds tasks whose management plan / planting management plan entities are not (yet) in the store. Observed crash sites include the location details tabs (via the Map), the tasks list, and the Crop Catalogue:taskSlice.js—Cannot set properties of undefined (setting 'planting_management_plan')ingetManagementPlanByPlantingManagementPlan(Immerproduceover anundefinedmanagement plan)taskSlice.js—Cannot read properties of undefined (reading 'location_id')in the plant/transplant branch oftaskEntitiesSelectorplantTaskSlice.js—Cannot destructure property 'management_plan_id' of 'plantTask.planting_management_plan' as it is undefined(Crop Catalogue);transplantTaskSlice.jshas the identical latent patternRoot cause
taskEntitiesSelectorand the by-management-plan-id selectors join tasks againstmanagementPlanSliceandplantingManagementPlanSlicewithout guards, assuming every referenced plan entity is loaded. That assumption cannot hold:GET /task/{farm_id}does not embedplanting_management_planinplant_task/transplant_task(it never has — the upsert ingetPlantingTasksAndPlantingManagementPlansSuccessSagareceives an empty list from this endpoint), and it never populatesmanagementPlanSliceat all. Any tasks fetch that is not preceded by a plans fetch can therefore store tasks with dangling plan references — e.g. when another user on the same farm has created a management plan since the last plans fetch.The crashes were reproduced with two users on one farm and confirmed in the debugger: at the moment of the throw, the crashing task referenced a
planting_management_plan_idabsent fromplantingManagementPlanEntities. The bug predates the locations refactor release (all three ingredients date from 2021-2022; verified empirically on the pre-release production commit).Fix
Make the task selector joins total over partial state — one rule at every cross-slice join: a task that references an entity not yet in the store joins nothing (or is dropped) and reappears when the entity loads.
getManagementPlanByPlantingManagementPlanreturnsundefinedwhen the management plan record is missing; both call sites filter these outtaskTypeis not in the store is dropped fromtaskEntitiesSelectoroutput (every consumer dereferencestaskTypeunconditionally)[])assigneejoin uses optional chaining onuserFarmEntities[farm_id]plantTasksByManagementPlanIdEntitiesSelector/transplantTasksByManagementPlanIdEntitiesSelectorskip tasks whose plan is unresolvedBehaviour consequence: a task whose plan entities have not arrived yet is temporarily excluded from task lists instead of crashing the page; it appears as soon as the plans fetch lands — the same end state the paired fetch always produced, without the crash window.
Out of scope (possible follow-up): embedding
planting_management_planin theGET /task/{farm_id}graph to shrink the window in which a task is unresolvable.Jira link: https://lite-farm.atlassian.net/browse/LF-5381
Type of change
How Has This Been Tested?
Two users on the same farm:
TypeErrorerror page, persisting across reloads. After the fix: pages render; the new plan's tasks appear once the page's own fetches complete.Also regression-checked the fully-loaded case: tasks list, task read-only view, and Crop Catalogue with all data fetched.
Checklist:
pnpm i18nto help with this)