The board grammar already parses per-part marks ([N marks] / "Total for Question N is M marks"), but they were dropped building the first-pass template and the row mapper hardcoded max_marks=0 — so every born-digital paper came back with zero marks for a teacher to re-key by hand. Thread the parsed mark through: bands.py derive_bands now carries each part's `marks`, template.build passes it into part_bands, and _map_first_pass_to_rows reads it via a defensive _safe_marks (non-negative int; unknown/None -> 0, so image-only OCR — which has no marks yet — is unchanged). Containers still roll up from parts. Adds test_auto_map_surfaces_born_digital_part_marks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Description
FastAPI + Python 3.12 backend for Classroom Copilot — auth, document processing, transcription sessions, LLM integration, Supabase-backed
Languages
Python
98.9%
Shell
0.8%
Jupyter Notebook
0.3%