## 1. Project Setup - [x] 1.1 Scaffold Vite + React + TypeScript project with `npm create vite@latest` - [x] 1.2 Install dependencies: `javascript-lp-solver`, `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/utilities` - [x] 1.3 Install dev dependencies: `vitest` for unit testing, `agent-browser` for interactive UI verification - [x] 1.4 Run `agent-browser install` to set up Chromium for headless browser automation - [x] 1.5 Configure Vite and TypeScript settings, verify dev server runs ## 2. Data Layer - [x] 2.1 Define TypeScript types: `ElectiveSet`, `Course`, `Specialization`, `MarkerType` ('standard' | 'S1' | 'S2'), `Qualification` - [x] 2.2 Create `src/data/specializations.ts` with all 14 specializations (id, name, abbreviation, requiredCourseId) - [x] 2.3 Create `src/data/electiveSets.ts` with all 12 elective sets (id, name, term, courseIds) - [x] 2.4 Create `src/data/courses.ts` with all 46 courses (id, name, setId, qualifications array with specId and marker type), transcribed from SPECIALIZATION_EVALUATION.md - [x] 2.5 Create `src/data/lookups.ts` with derived indexes: coursesBySet, specsByCourse, coursesBySpec (computed once at module load) - [x] 2.6 Write data validation tests: verify 46 courses, 12 sets, 14 specs, 10 S1 markers, 7 S2 markers, 4 required course gates, and per-specialization "across sets" counts match the reachability table ## 3. Optimization Engine — Core - [x] 3.1 Implement `checkFeasibility(selectedCourses, targetSpecs, s2Choice?)` — builds LP model and returns feasible/infeasible with allocation details - [x] 3.2 Implement `preFilterCandidates(selectedCourses, openSets)` — removes specs missing required courses, returns candidate list - [x] 3.3 Implement `enumerateS2Choices(selectedCourses)` — returns array of S2 course options (including null) for Strategy enumeration - [x] 3.4 Implement `computeUpperBounds(selectedCourses, openSets)` — upper-bound credit potential per spec ignoring sharing - [x] 3.5 Write unit tests for LP feasibility: feasible allocations, infeasible allocations, required course gating, S2 constraint enforcement ## 4. Optimization Engine — Modes - [x] 4.1 Implement `maximizeCount(selectedCourses, ranking, openSets)` — enumerate subsets size 3→0, check feasibility, pick best priority score - [x] 4.2 Implement `priorityOrder(selectedCourses, ranking, openSets)` — iterate specs in rank order, greedily add if feasible - [x] 4.3 Implement `determineStatuses(selectedCourses, openSets, achieved)` — assign achieved/achievable/missing_required/unreachable per spec - [x] 4.4 Write unit tests for both modes: verify correct achieved sets, priority tie-breaking, status determination, edge cases (no pins, all pins) ## 5. Decision Tree — Web Worker - [x] 5.1 Create `src/workers/decisionTree.worker.ts` — receives selected courses + ranking + mode, computes ceiling per open set per course choice - [x] 5.2 Implement ceiling computation with early termination (stop at 3-spec ceiling) - [x] 5.3 Implement impact ordering: compute variance in ceiling outcomes per open set, sort descending (chronological tiebreak) - [x] 5.4 Implement progressive messaging: worker posts results per open set as each completes - [x] 5.5 Implement fallback: skip enumeration when 10+ sets are open, return upper-bound reachability only - [x] 5.6 Write unit tests for ceiling computation and impact ordering logic (testable without worker wrapper) ## 6. State Management - [x] 6.1 Define app state type: `{ ranking: string[], mode: 'maximize-count' | 'priority-order', pinnedCourses: Record }` - [x] 6.2 Implement `useReducer` with actions: `reorder`, `setMode`, `pinCourse`, `unpinCourse` - [x] 6.3 Implement localStorage persistence: save on state change, restore on load, fallback to defaults on parse error - [x] 6.4 Implement derived computation: `useMemo` for upper bounds + LP optimization on pinned courses (main thread) - [x] 6.5 Implement Web Worker integration: debounced 300ms dispatch to decision tree worker, progressive state updates from worker messages ## 7. UI — Specialization Ranking - [x] 7.1 Build `SpecializationRanking` component: vertical sortable list of 14 specializations using @dnd-kit/sortable - [x] 7.2 Add drag handle, visual drag feedback (elevated/semi-transparent item, drop indicator) - [x] 7.3 Add keyboard reordering support via @dnd-kit accessibility features - [x] 7.4 Build `ModeToggle` component: two-option toggle with brief descriptions for Maximize Count and Priority Order - [x] 7.5 Verify with agent-browser: snapshot ranking list shows 14 specializations, drag reorder works, mode toggle switches active state ## 8. UI — Course Selection - [x] 8.1 Build `CourseSelection` component: 12 elective sets grouped by term (Spring/Summer/Fall sections) - [x] 8.2 Build `ElectiveSet` component: shows set name, list of courses as selectable options, pin/unpin interaction - [x] 8.3 Implement visual state indication: open sets (dashed border, all courses shown) vs pinned sets (selected course prominent, unpin control) - [x] 8.4 Verify with agent-browser: snapshot shows 12 sets grouped by term, pin a course and confirm set updates to pinned state, unpin and confirm it reverts ## 9. UI — Results Dashboard - [x] 9.1 Build `ResultsDashboard` component: displays 14 specializations in priority rank order with status badges (achieved/achievable/missing_required/unreachable) - [x] 9.2 Build credit progress display: progress bar toward 9-credit threshold, show allocated vs potential credits - [x] 9.3 Build expandable allocation breakdown for achieved specializations: list contributing courses and credit amounts - [x] 9.4 Build `DecisionTree` component: open sets ordered by impact, each showing course choices with ceiling outcomes - [x] 9.5 Add loading states for decision tree: show upper-bound fallback while Web Worker computes, progressive update as results arrive - [x] 9.6 Build mode comparison display: when modes disagree, show both outcomes with explanation - [x] 9.7 Build mutual exclusion warnings: highlight SBI/E&I conflict in Spring Set 4, and other required-course conflicts - [x] 9.8 Verify with agent-browser: pin several courses, snapshot results dashboard to confirm status badges, credit progress, and allocation breakdown render correctly ## 10. App Layout & Integration - [x] 10.1 Build `App` component layout: specialization ranking panel, course selection panel, results dashboard panel - [x] 10.2 Wire state management to all components: ranking changes, pins, mode toggle all trigger recalculation - [x] 10.3 Verify end-to-end flow: rank specs → pin courses → see results → explore decision tree - [x] 10.4 Add basic CSS styling: clean layout, status colors, responsive enough for desktop/tablet - [x] 10.5 Full agent-browser walkthrough: open app, reorder specializations, toggle mode, pin courses across multiple sets, verify results dashboard shows correct achieved/achievable statuses, explore decision tree, take final screenshot