codebase-doctor migration dossier

Session 3fd51510 · generated 2026-09-26 10:19:05 UTC

react ^17.0.2 → 18.3.1

codebase-doctor-sandbox/pantry-list · codebase-doctor/react-18.3.1-upgrade from main

Rules loaded

  1. Analyse — done
  2. Rules — done
  3. Risk — current step
  4. Plan — not started
  5. Approve — not started
  6. Implement — not started
  7. Verify — not started
  8. Pull request — not started
11
files use react
16 imports · 19 API usages
—
files need attention
risk not scored yet
8
breaking changes apply
3 automated · 5 manual/review
not run
verification
verify_migration has not run

01Risk & priority

Which files matter most, scored from concrete API evidence.

Risk has not been scored yet. calculate_migration_blast_radius scores every file from concrete API evidence (see the severity guide).

02Breaking changes

The rules that apply to this repository — and why.

high react-bc-1 automated confirmed by docs Not started

ReactDOM.render() is deprecated in React 18 (the app keeps running in legacy React 17 mode) — replace with createRoot().render()

0 files

high react-bc-2 automated confirmed by docs Not started

ReactDOM.hydrate() is deprecated in React 18 (legacy mode) — replace with hydrateRoot()

0 files

medium react-bc-3 automated Not started

act() from react-dom/test-utils is deprecated — import act from 'react' (available from React 18.3)

0 files

medium react-bc-4 manual confirmed by docs Not started

Automatic batching: setState calls in timeouts/promises/native handlers are now batched — may affect code or tests relying on intermediate renders

How to fix Review any tests that assert on intermediate render states inside setTimeout, Promise.then, or native event handlers. Wrap those assertions in act() or use flushSync from 'react-dom' to opt out of automatic batching where needed.

0 files

low react-bc-6 manual confirmed by docs Not started

Strict Mode now double-invokes effects (mount → unmount → mount) in development to surface side effects

How to fix Audit useEffect, useLayoutEffect, and class lifecycle methods for non-idempotent side effects (network requests, analytics calls, subscriptions). Ensure cleanup functions are implemented so double-invocation does not cause observable problems in development.

0 files

low react-bc-7 manual Not started

ReactDOM.unstable_batchedUpdates is redundant under React 18 automatic batching

How to fix With React 18's automatic batching, explicit calls to unstable_batchedUpdates are no longer needed in most cases. Remove them and verify behaviour. If you need to force synchronous rendering, use flushSync from 'react-dom' instead.

0 files

medium react-bc-8 manual confirmed by docs Not started

ReactDOM.unmountComponentAtNode() is deprecated in React 18 — call root.unmount() on the root returned by createRoot()

How to fix Keep the root returned by createRoot(container) and call root.unmount() instead of unmountComponentAtNode(container). In tests, unmount the root the test created (React Testing Library unmounts automatically).

0 files

low react-bc-12 manual confirmed by docs Not started

Tests that render with react-dom directly need globalThis.IS_REACT_ACT_ENVIRONMENT = true under React 18

How to fix In the test setup file (e.g. setupTests.js / jest.setup.js), set globalThis.IS_REACT_ACT_ENVIRONMENT = true; so React 18 knows it runs in an act-aware test environment. React Testing Library ≥ 13 sets this automatically for tests that use it.

0 files

03Compatibility

Declared packages whose peer ranges could block the install.

Checked 602 packages via package-lock.json (lockfileVersion 3).

PackageRequiresSourceResolution
@testing-library/react@12.1.5react <18.0.0lockfileauto upgraded to ^14.3.1 in the dependency step

04Migration plan

What will change, in order, and what has happened so far.

No plan yet. generate_migration_plan orders the work (dependencies first, then high-severity changes) and waits for your approval.

05Affected files

Every file that uses the package family, with line-level evidence.

11 files

src/App.jsx 0
LineUsageSourceRules
1import reactimport React, { useReducer } from 'react';—
1useReducer · reactimport React, { useReducer } from 'react';—
23useReducer · reactconst [items, dispatch] = useReducer(itemsReducer, []);—
src/App.test.jsx test 0
LineUsageSourceRules
1import reactimport React from 'react';—
src/components/AddItemForm.jsx 0
LineUsageSourceRules
1import reactimport React, { useState } from 'react';—
1useState · reactimport React, { useState } from 'react';—
4useState · reactconst [name, setName] = useState('');—
src/components/ItemList.jsx 0
LineUsageSourceRules
1import reactimport React from 'react';—
3Component · reactexport default class ItemList extends React.Component {—
src/components/SyncStatus.jsx 0
LineUsageSourceRules
1import reactimport React, { useState } from 'react';—
1useState · reactimport React, { useState } from 'react';—
7useState · reactconst [status, setStatus] = useState('idle');—
8useState · reactconst [syncedAt, setSyncedAt] = useState(null);—
src/components/SyncStatus.test.jsx test 0
LineUsageSourceRules
1import reactimport React from 'react';—
src/index.jsx 0
LineUsageSourceRules
1import reactimport React from 'react';—
2import react-domimport ReactDOM from 'react-dom';—
5render · react-domReactDOM.render(—
6StrictMode · react<React.StrictMode>—
src/legacy/store.js 0
LineUsageSourceRules
1import react-domimport ReactDOM from 'react-dom';—
13unstable_batchedUpdates · react-domReactDOM.unstable_batchedUpdates(() => {—
src/legacy/toast.jsx 0
LineUsageSourceRules
1import reactimport React from 'react';—
2import react-domimport ReactDOM from 'react-dom';—
17render · react-domReactDOM.render(<Toast message={message} />, host);—
19unmountComponentAtNode · react-domReactDOM.unmountComponentAtNode(host);—
src/legacy/toast.test.jsx test 0
LineUsageSourceRules
1import reactimport React from 'react';—
2import react-domimport ReactDOM from 'react-dom';—
3import react-dom/test-utilsimport { act } from 'react-dom/test-utils';—
3act · react-dom/test-utilsimport { act } from 'react-dom/test-utils';—
13act · react-dom/test-utilsact(() => {—
18act · react-dom/test-utilsact(() => {—
27act · react-dom/test-utilsact(() => {—
28render · react-domReactDOM.render(<p>host</p>, container);—
src/ssr-entry.jsx 0
LineUsageSourceRules
1import reactimport React from 'react';—
2import react-domimport ReactDOM from 'react-dom';—
6hydrate · react-domReactDOM.hydrate(<App />, document.getElementById('root'));—

06Changes

Each step's commit on the migration branch.

Nothing has been changed — the plan is not approved, and the backend refuses to modify the repository until it is.

07Verification

Does the upgraded code pass the repository's own checks?

Verification has not run yet. It runs after the plan is approved and applied: verify_migration checks the installed versions, then runs the repository's own lint, test and build scripts.

08Remaining work

What still needs a human before (or after) merging.

The plan has not been generated yet.

09Metrics

Measured values, labelled estimates, and what is not measured.

measured

Files using react11
Files with breaking-change evidencenot calculated
Files changed on branchbranch not created
Steps applied automatically0 / 0
Steps completed manually0
Steps still open (manual / skipped / failed)0
Elapsed session time (wall-clock)0 min

estimate

Manual effort
~0 h0 affected files × 30 min/file (heuristic, not benchmarked)
Time saved
~0 hestimated manual effort − measured elapsed time

not measured

  • Bobcoin consumption — not measured (not exposed to the MCP server)
  • Accuracy — not measured (no ground-truth benchmark)

10Repository

How the repository was analysed.

Repositorycodebase-doctor-sandbox/pantry-list
Default branchmain
Migration branchcodebase-doctor/react-18.3.1-upgrade
Languagejavascript
Package managernpm
Test frameworkjest
Lint / test / buildnpm run lint · npm run test · npm run build
Source files scanned13
Rule setreact-17-to-18.json + your migration docs
Session3fd51510-5cd8-41f8-8271-285c542bb72f