The README now documents the daily workflow (working date, live mode
vs printed lists, regenerate semantics, full day-editor editability),
describes cycle mode's rolling rotation accurately, repairs the
custom-parameters section, and points to the saltire testing guide,
which gains resume-after-a-break instructions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Everything on the home page — availability counts, live mode, the
calls editor, and list generation — now targets a selectable working
date instead of being fixed to today, with quick links to upcoming
scheduled class days. Printing tomorrow's list a day in advance is
just switching the date and generating; other days' data is
untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generating a call list is non-destructive by intent: the button reads
Regenerate when an unused list exists and replaces it freely, with a
confirmation only when the day already has recorded outcomes (which
are always kept). The print view shows resolved calls' outcomes,
offers generate/regenerate in place, and the home page links to the
existing list. The day editor now supports adding calls after the
fact (any roster student, with status/assessment/note), completing
full editability: add, edit, delete.
Cycle mode is now a true rolling rotation driven by non-skipped call
counts: batches of n take the next students of the current pass,
remainder batches come up short rather than wrapping, a new pass
starts when everyone has been called, and the cycle continues across
lists and class days. Live mode uses the same rule.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The real-handshake test against the saltire LTI platform emulator
turned up a launch bug dev mode cannot reach: pylti1p3's Flask adapter
requires the application to supply the cookies_allowed_js_check.html
template used by enable_check_cookies(), and without it every OIDC
login 500s. The template tests whether cookies survive, then re-enters
the login flow or offers a new-window fallback.
docs/SALTIRE.md records the verified test setup: local HTTPS with a
self-signed certificate, the platform description for
instance/lti_config.json, the saltire-side configuration, and the
session-id caveat on saltire's token/jwks URLs. The 2026-08-01 run
verified the full OIDC handshake, JWT validation, NRPS roster sync
over the wire, and instructor/learner role routing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports the timing-neutral foregone-participation grading scheme from
participation_grades.R: answer quality (per-course level points) minus
a deduction for participation foregone through unavailability,
estimated by Monte Carlo simulation of the actual weighted draw and
averaged over when absences fall, plus a small form-filing incentive
for drawn-while-absent-without-opt-out days. Reason-blind and
luck-protected; zero-answer students floor to 0. Parameters
(allowance in SD units, passing line, form penalty, simulation
size/seed) are course settings. Verified against the R engine's
rendered 2026q2 reports via the new import-legacy command: quality and
availability match exactly, finals within Monte Carlo noise; dropped
students import as inactive enrollments and are excluded identically.
Grades are computed on demand into stored GradeRun snapshots and
reviewed on a grades page with CSV export and per-student reports
(also served to students via a publish toggle). Display scales map
points to UW 4.0, a threshold table (one-click import of the Canvas
course grading scheme), or raw points. Gradebook passback via AGS
sits behind a settings toggle with a review-then-push flow.
Opt-out withdrawals are now soft-deletes with a withdrawn_at audit
trail, and close when class begins (class days gained optional start
times), so availability records cannot be rewritten after the fact.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Instructor participation report: per-student histograms, outcome mix
by class day, and a sortable table including the fairness ratio
(answered calls over questions present for, with opt-out days out of
the denominator), plus CSV exports of students, calls, and opt-outs.
Assessment scales are now per-course data: ordered levels with labels
and points out of 100 (defaults carry the old R grading values), with
calls referencing levels by id so renames follow through to history.
Renaming, re-pointing, reordering, and adding levels are always
allowed; deleting a level in use by recorded calls is blocked.
Pronouns and course term dates come from Canvas custom variable
substitutions, at launch and roster-wide via rlid-scoped NRPS; the
student page notes that names/pronouns are Canvas-sourced. Rosters
can also be refreshed outside launches: a "Sync roster now" button
and a sync-rosters CLI command for an hourly cron job, skipping ended
courses. Alembic now runs SQLite-compatible batch migrations with a
constraint naming convention.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Student page with a standing summary, a class-comparison histogram
(zero-dependency HTML/CSS) with a plain-language fewer/same/more
sentence, opt-out management with withdrawal of future dates, and a
call history that respects the per-course assessment-visibility
setting and never shows pending or skipped calls. Opt-outs validate
against a new per-course class-day schedule (range generator plus
individual add/remove for holidays), since Canvas has no structured
meeting-day data; courses without a schedule fall back to a free date
picker. Dev mode seeds a Tue/Thu pattern.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live mode with resolve-before-next call flow and one-tap outcomes
(assessments, missing, skip); printable numbered call lists with
pictures and a blank notes column; a day editor for after-class
outcome entry, replacing hand-editing of call_list TSVs; and a
per-course settings page (selection mode, weight factor, assessment
visibility). Selection honors opt-outs and the course's mode: weighted
draws use full-course answered-call history, cycle mode calls everyone
once per day before starting over and treats skips as never called.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
OIDC login, launch, and JWKS endpoints built on pylti1p3next's Flask
adapter, with launch-claim processing split into a testable module.
Instructor launches refresh the roster through NRPS; the sync code is
source-agnostic and also drives the dev-mode fake roster. Dev mode
(COLDCALL_DEV_MODE=1) provides fake instructor and student personas
that set up the same session state as a real launch, so the rest of
the app can be developed before a Canvas Developer Key exists.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flask application skeleton with SQLAlchemy models for courses (including
per-course settings), students, enrollments, opt-outs, and calls; the
weighted and cycle selection logic ported from the manual coldcall
scripts; alembic migrations; and a pytest suite covering selection
behavior and the model query helpers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>