Remove the unsafe `# type: ignore` suppression on line 111 of
`legacy_migrator.py` and replace it with an explicit
`assert existing_plan.id is not None` statement. This provides
proper type narrowing to the type checker while preserving the
logical correctness guaranteed by the preceding `if existing_plan:`
guard.
Also adds a new BDD scenario in `legacy_migrator_coverage.feature`
that explicitly exercises the code path where an existing plan with
a non-None id is found during migration, verifying the assert-based
type narrowing works correctly end-to-end.
ISSUES CLOSED: #3051
Move ctx.plans.get_all_for_project(project.id) outside the plan
iteration loop in LegacyDataMigrator.migrate_project_data to eliminate
an N+1 database query pattern.
Previously, the method fetched all plans from the database on every
iteration of the plans loop, resulting in O(N) queries where N is the
number of plans in the legacy plans.json file. For projects with many
plans, this caused significant unnecessary database load during migration.
The fix fetches all existing plans once before the loop begins, then
uses the in-memory list for duplicate detection on each iteration.
Also verified no other similar N+1 patterns exist in LegacyDataMigrator.
Added a new Behave scenario 'get_all_for_project is called only once for
multiple plans' that patches the repository method to count invocations
and asserts exactly one call regardless of how many plans are migrated.
ISSUES CLOSED: #3047