MUSA Graderv0.1.0

User guide

Results and exports

Each grading run is a session, saved under results/<session_id>/. The session id is the assignment id plus a timestamp, for example hw1_20261006_142233.

Session directory#

results/<session_id>/
├── grades.csv                 student_id, score, execution status, review flags
├── grading_session.json       full state; reload it from the Overview page
├── summary.json               class summary
├── flagged_submissions.csv    the review queue
├── class_report.md            the class overview as markdown
├── feedback/<student>.md      student-facing feedback
├── executed_notebooks/        probe cells stripped
└── raw_results/<student>.json rubric-level detail with evidence

The probe cells are removed from executed notebooks before they are saved, so nothing in results/ reveals the hidden tests.

Result schema#

Each raw_results/<student>.json is a serialised SubmissionResult:

{
  "student_id": "student_003",
  "status": "graded",              // pending | graded | error | skipped
  "needs_review": true,
  "total_score": 71.5,
  "automatic_total": 71.5,
  "max_score": 100.0,
  "confidence": 0.75,              // lowest item confidence
  "review_reasons": ["Center City split correctly: lost 7.5 of 15"],
  "discovery_warnings": [],
  "execution": {
    "success": true, "attempted": true, "timeout": false,
    "execution_time_seconds": 8.4, "mode": "docker",
    "error_cell": null, "error_message": null
  },
  "items": [
    {
      "rubric_id": "center_city_split",
      "name": "Center City split correctly",
      "type": "deterministic",
      "points_possible": 15.0,
      "automatic_score": 7.5,
      "final_score": 7.5,
      "status": "partial",
      "confidence": 0.75,
      "feedback": "...",
      "evidence": { "...": "..." },
      "manual_override": false,
      "manual_score": null,
      "override_reason": ""
    }
  ]
}

The values above are illustrative. Every item keeps both automatic_score and final_score, so a manual override never destroys the automated result.

Exports#

The Export page offers these downloads, all built by GradingSession:

DownloadMethodContents
Grades CSVgrades_csv()One row per student: student_id, display_name, total_score, max_score, percentage, letter, execution_status, manual_review, reviewed, manual_override, confidence
Rubric CSVrubric_csv()One row per student per rubric item
Flagged CSVflagged_csv()The review queue
Feedback ZIPfeedback_zip()Every feedback/<student>.md
Session archivearchive_zip()The whole session directory

Reloading and regrading#

A saved session can be reloaded from the Overview page, or in Python:

from grader.results import GradingSession, list_sessions

for entry in list_sessions():
    print(entry["session_id"], entry["assignment_name"], entry["submissions"])

session = GradingSession.load("results/hw1_20261006_142233")
session.set_override("student_003", "center_city_split", 15,
                     reason="Alternative valid implementation.")
session.mark_reviewed("student_003")
session.save()

Regrading (after a rubric fix, for example) regenerates every automatic score. With overrides preserved, your decisions are put back on top:

service.regrade(session, candidates, preserve_overrides=True)

See GradingService.regrade.