//! # coursebank //! //! A tool for running the assessment side of a course as version-controlled data. //! //! The premise is that the artifacts you already produce (questions, exams, //! grading exports) are worth treating as a dataset rather than as a pile of //! documents. Once they are, several things you cannot otherwise do become //! routine: knowing which questions actually discriminate, catching a poorly worded //! item from the pattern of who chose which distractor, telling a student which //! misconception their specific wrong answer indicates, and never accidentally //! reusing the same question three terms in a row. //! //! ## The four kinds of file //! //! | File | Holds | Written by | //! |:--|:--|:--| //! | `course.yaml` | identity, policy, objectives, lectures | you | //! | `banks/*.yaml` | items, with design intent and pooled statistics | you, then `calibrate` | //! | `assessments/*.yaml` | what was given, to whom, when | `assemble`, then you | //! | `data/*.parquet` | one row per student per item | `ingest` | //! //! Three of the four are hand-editable YAML meant to be reviewed in a pull request. //! Only the response data is machine-only, and it is stored in an open columnar //! format so pandas, polars, R, and DuckDB can all read it without this tool. //! //! ## The loop //! //! ```text //! author items ──▶ validate ──▶ lint ──▶ assemble ──▶ export ──┐ //! ▲ │ //! │ administer //! │ │ //! calibrate ◀── analyze ◀── ingest ◀───────────────────────────┘ //! │ //! └──▶ report (students and cohort) //! ``` //! //! The arrow back from `calibrate` to authoring is the point of the whole design. //! Statistics written onto the item are there the next time you consider using it, //! and they accumulate across terms: twenty-four students tells you very little, //! but ninety-six across four terms tells you something real. //! //! ## Design commitments //! //! Assessment records are the single source of truth for reuse history. There //! is no separate ledger file, because a ledger duplicates what the records must //! already get right and then drifts from it. [`assessment::History`] derives usage //! by scanning the records. //! //! **Fingerprints cover only what a student saw.** Retag an item's metadata and its //! pooled statistics stay valid; reword the stem and they are marked stale. See //! [`item::Item::fingerprint`]. //! //! **Validation reports everything at once.** Fixing one typo per run is not a //! workflow. [`error::Error::Invalid`] carries a list. //! //! **Validation and linting are separate.** [`bank::BankFile::validate`] enforces //! what must be true; [`lint`] advises on what is usually a mistake, and every rule //! has a code you can silence. //! //! **Small samples are labelled as such.** Every statistic computed from a class of //! twenty-five is reported with the caveat it deserves rather than three decimal //! places of false precision. //! //! ## Dependency posture //! //! Deliberately small: serde, a YAML parser, clap, thiserror, and csv, plus arrow //! and parquet behind a default-on feature that can be switched off. Dates, PRNG, //! hashing, ZIP writing, and the psychometrics are implemented here rather than //! pulled in — see [`date`], [`rng`], [`hash`], [`zipfile`], [`irt`]. For a tool //! whose job is to still open a course repository in five years, that tradeoff //! favours fewer moving parts. //! //! ## Where to start //! //! This page describes the shape of the crate. For a walkthrough, [`guide`] holds //! setup, authoring, and tutorials, starting with [`guide::setup`]. #![warn(missing_docs)] #![forbid(unsafe_code)] // A broken link in a tutorial is a silent lie about the API, so it fails the build // rather than warning into a log nobody reads. #![deny(rustdoc::broken_intra_doc_links)] #![warn(rustdoc::invalid_codeblock_attributes)] #![warn(rustdoc::invalid_html_tags)] #![warn(rustdoc::bare_urls)] #![warn(rustdoc::private_intra_doc_links)] // Lets `cargo doc` mark feature-gated items with the feature that enables them, on // a nightly toolchain or on docs.rs. Ignored elsewhere. #![cfg_attr(docsrs, feature(doc_cfg))] pub mod analysis; pub mod authoring; pub mod data; pub mod error; pub mod export; pub mod guide; pub mod model; pub mod util; pub use util::{date, hash, markup, rng, yaml, zipfile}; pub use model::{assessment, bank, catalog, course, item, taxonomy}; pub use authoring::{jsonschema, lint, select}; #[cfg(feature = "parquet")] pub use data::store_parquet; pub use data::{canvas, gradescope, responses, store}; pub use analysis::{calibrate, classical, irt, students}; pub use export::{qti, report, typst}; pub use catalog::Catalog; pub use course::{CourseFile, Layout, SCHEMA_VERSION}; pub use error::{Error, Result}; pub use item::Item; pub use taxonomy::{CognitiveProcess, ErrorType, Flag, Format, Level, Status}; /// Version of package. pub const VERSION: &str = env!("CARGO_PKG_VERSION");