Summary
Recipes/RecipeSession.cs is 651 lines against the project's 300-line convention and owns five concerns: undo/redo history (27-29, 606-622), dirty-flag state, seven mutation entry points, per-cell parse/validate orchestration (515-555), formula recalculation gating (557-577), and sync notification (624-630). Every feature touching editing, validation, or sync converges on this file, and the mutation methods repeat the same validate-index/get-action/apply skeleton six times.
Suggested fix
Two extractions, no public API change:
RecipeHistory — undo/redo stacks + dirty flag;
StepMutationValidator — ParseAndValidateColumnValue + index checks (collapses the six repeated skeletons).
RecipeSession shrinks to orchestration and drops under the limit.
Related cleanup in the same pass
RecipeSession.cs:200 — LoadAsCurrentValidated(Recipe, ImportedRecipeValidator) takes the validator as a method parameter although it is a DI singleton both callers (PlcLifecycleManager, RecipeCoordinator) already inject themselves. Constructor-inject it into RecipeSession and drop the parameter; callers stop needing the dependency at all.
Note: the sync-notification concern (624-630) is addressed separately by the Recipes<->Plc inversion issue; do that one first or coordinate.
Summary
Recipes/RecipeSession.csis 651 lines against the project's 300-line convention and owns five concerns: undo/redo history (27-29, 606-622), dirty-flag state, seven mutation entry points, per-cell parse/validate orchestration (515-555), formula recalculation gating (557-577), and sync notification (624-630). Every feature touching editing, validation, or sync converges on this file, and the mutation methods repeat the same validate-index/get-action/apply skeleton six times.Suggested fix
Two extractions, no public API change:
RecipeHistory— undo/redo stacks + dirty flag;StepMutationValidator—ParseAndValidateColumnValue+ index checks (collapses the six repeated skeletons).RecipeSessionshrinks to orchestration and drops under the limit.Related cleanup in the same pass
RecipeSession.cs:200—LoadAsCurrentValidated(Recipe, ImportedRecipeValidator)takes the validator as a method parameter although it is a DI singleton both callers (PlcLifecycleManager,RecipeCoordinator) already inject themselves. Constructor-inject it intoRecipeSessionand drop the parameter; callers stop needing the dependency at all.Note: the sync-notification concern (624-630) is addressed separately by the Recipes<->Plc inversion issue; do that one first or coordinate.