# Cosimo

Cosimo is a spaced-repetition system for learning prompt/response pairs with a
screen-reader-accessible desktop interface. Accessibility is a hard project
requirement, not a later polish step.

The current application uses `wxdragon` on top of wxWidgets for the GUI,
stores editable learning content in a plain-text deck file, and stores review
history in SQLite.

## Project Goals

- Make the full review flow usable with screen readers and keyboard input.
- Keep learning content human-editable without pushing users through a database
  editor.
- Keep review history, ratings, and scheduling state separate from the editable
  deck content.
- Favour native controls and platform accessibility APIs over custom-drawn UI.

## Current State

The repository currently contains:

- a deck format for prompt/response pairs
- a typed Rust data model for review ratings
- SQLite-backed review event storage
- scheduled review sessions with configurable minimum session size
- a wxdragon desktop review UI for a single deck file
- pre-cycle deck review with a prompt list on the start screen
- ready-list filtering, including duplicate prompt/response filters, multiple
  sort criteria, sort direction, and per-card details
- card management from the GUI: add, edit, remove
- reversible cards with independent reverse-direction review history and
  scheduling
- a learning dashboard with separate standard/reverse/total sections when a
  deck contains reverse cards
- recent-deck reopening from `File -> Recent Decks`
- automatic deck and review-database backup options
- language selection for English, Spanish, and Galician
- end-of-pass statistics and saved text reports
- flagged-card review, deferral, suspension, and non-reversible card markers
- optional sound notifications and minimise-to-system-tray behaviour

## Licence

Cosimo is released under the GNU General Public Licence version 3. See
[LICENSE](LICENSE).

## Review Model

For a user-facing introduction to studying with Cosimo, see
[docs/user-guide.md](docs/user-guide.md).

Release notes are kept in [CHANGELOG.md](CHANGELOG.md).

Each datum contains:

- a prompt or question
- a response or answer

Before seeing the response, the user may record a guess:

- `1` Don't know
- `2` Probably don't know
- `3` Probably know
- `4` Certainly know
- Space / `Reveal Response` records no guess and stores `Not answered`

After seeing the response, the user records feedback:

- `1` Again
- `2` Hard
- `3` Good
- `4` Easy

The review UI also supports:

- `0` End this pass now
- `e` Edit the current card after its response has been revealed
- `Ctrl-F` Flag or unflag the current card during review
- `Ctrl-D` Defer the current card until tomorrow before revealing the response

Before a pass starts, Cosimo shows:

- the number of cards that would be scheduled now
- the configured minimum cards per session
- a navigable list of cards labelled by prompt
- a text filter for narrowing the prompt list by prompt or response
- `Add Card`, `Edit Selected`, and `Remove Selected` controls
- `Alt-S` to start the pass
- `Alt-L` to move to the text filter
- `F5` to refresh the ready summary, ready-list filters, and status bar
- `Ctrl-F` to flag or unflag the selected card
- `Alt-T` to force-start a full-deck pass in random order
- `Alt-Q` to quit from the ready screen in English, or `Alt-S` in Spanish and
  Galician

Cards can be marked reversible before a pass starts. A generated reverse card
asks for the original response and expects the original prompt, using separate
review history and scheduling state from its parent card. Cosimo blocks reverse
generation for cards whose response is duplicated by another card, because the
reverse prompt would be ambiguous. The ready-list duplicate-response filter
helps find those cards before using bulk reversal, and `Cards -> Undo Last Bulk
Reversal` can remove the reverse cards created by the latest bulk batch while
leaving manual reverse cards and review history in place.

The ready summary, ready-list filters, and status bar refresh about once per
minute while the ready screen is open, so newly due cards become available for
scheduled start without reopening the deck.

At the end of a pass, or when the pass is ended early, Cosimo shows a
statistics dialogue summarising the ratings from that pass. The dialogue reports
counts and percentages and then offers `Continue` to return to the ready screen.

## Scheduling

Normal `Start` builds a scheduled review queue:

- due cards are reviewed first
- if fewer cards are due than the configured minimum cards per session, Cosimo
  randomly fills the queue from the remaining cards
- if the minimum is `0`, only due cards are scheduled

Cosimo uses an FSRS-style spaced-repetition scheduler. It stores per-card memory
state in the review database, including difficulty, stability, due date,
repetitions, and lapses. Missed or wrong answers move a card back toward
learning; correct answers increase stability and make later intervals longer.

`Force Start` ignores due status and builds a randomised queue containing all
cards that are not suspended or deferred. This gives the user a way to study
even when no cards are due, while still respecting cards the user has
explicitly set aside.
Suspended cards are marked in the ready list, can be toggled from the Cards
menu, the ready-list context menu, or Ctrl+S while the ready list has focus,
and are ignored by the status bar when it reports the next due review.
Flagged cards are also marked in the ready list and can be shown with the
flagged-card filter, but flags do not affect scheduling. Flagging is available
from Ctrl-F, the Cards menu, the ready-list context menu, and review buttons
after the confidence or recall ratings.
`Review Flagged` starts an unscheduled pass through flagged cards that are not
suspended or deferred. Deferral is also available from the ready list and
during the prompt phase of a pass before the answer has been revealed.

The minimum cards per session, automatic deck-backup policy, review database
backup policy, sound notifications, and minimise-to-tray behaviour are set in
`File -> Options` and are persisted in `cosimo.ini`.

## Repository Layout

For a fuller map of the codebase, see [architecture.md](architecture.md).

- [src/model.rs](src/model.rs): datum, rating, and review types
- [src/deck_format.rs](src/deck_format.rs): human-editable deck parser and formatter
- [src/review_store.rs](src/review_store.rs): SQLite review storage
- [src/scheduler.rs](src/scheduler.rs): due-card scheduling and minimum-session fill
- [src/localization.rs](src/localization.rs): message catalogue and locale selection
- [src/main.rs](src/main.rs): wxdragon application
- [decks/deck.cosimo-deck](decks/deck.cosimo-deck): default deck file used by the GUI
- [ui/main.xrc](ui/main.xrc): main review window
- [ui/card_editor_dialog.xrc](ui/card_editor_dialog.xrc): add/edit card dialogue
- [ui/options_dialog.xrc](ui/options_dialog.xrc): language and session options
- [ui/stats_dialog.xrc](ui/stats_dialog.xrc): pass statistics dialogue

User-facing documentation lives in [docs/user-guide.md](docs/user-guide.md)
and [docs/troubleshooting.md](docs/troubleshooting.md).

## Deck Format

Cosimo uses a plain-text deck format designed to stay editable by hand.

Example:

```text
Capital of Spain
---
Madrid
=1=

Translate this sentence:
I opened the window.
---
Abri la ventana.
=2=
```

Rules:

- `---` separates prompt from response
- `=number=` ends one card and stores its stable card identity
- legacy `===` terminators are accepted and upgraded automatically when the app
  opens the deck
- prompts and responses may span multiple lines
- editing prompt or response text preserves the numbered identity
- review history does not live in the deck file

## Runtime Files

- `decks/`: default portable deck directory beside the application
- `decks/deck.cosimo-deck`: default editable learning content
- `decks/deck.reviews.sqlite3`: review history and scheduling database for the default deck
- `cosimo.ini`: persisted application settings, the most recently opened deck
  path, and the recent-decks list

These default runtime paths are resolved relative to the application executable,
not the shell or shortcut working directory. If the default deck is missing,
Cosimo creates an empty one on startup.

Older beta builds used `cosimo-settings.txt` and `cosimo-last-open-deck.txt`.
When Cosimo finds either file, it migrates their contents into `cosimo.ini` and
then removes the old file.

SQLite review databases are runtime state and are ignored by Fossil.

## Backup and Recovery

Back up each `.cosimo-deck` file and its matching `.reviews.sqlite3` file. The
deck file contains the editable prompts and responses. The review database
contains scheduling state, ratings, and review history.

Cosimo also keeps automatic deck-content backups. Before it overwrites an
existing deck file, it copies the current version into the app-level `backups`
directory beside the executable. Backup names use a global rising number and
the deck name, such as `backups/000001-deck.cosimo-deck`. The
`backups/index.txt` file records each backup filename and the original deck
path. These automatic backups protect card text from accidental edits or
migration mistakes, but they do not include review history.

The deck backup option in `File -> Options` controls automatic deck-content
backups:

- `Full`: keep every automatic deck backup.
- `Last only`: keep only the newest automatic backup for each original deck
  path.
- `None`: do not create automatic deck backups.

The review database backup option controls whether Cosimo keeps one automatic
review-database backup per review database. When set to `On session start`,
Cosimo refreshes that retained backup in the app-level `backups` directory when
a review pass starts. The database backup index is
`backups/review-db-index.txt`. When set to `Off`, Cosimo does not create or
refresh review-database backups. Bulk reversible-card creation is also treated
as a significant database change: when review-database backups are enabled,
Cosimo refreshes the retained backup before writing and warns that the retained
backup will be overwritten.

`File -> Reclaim Database Space` runs SQLite `VACUUM` on the review database
without deleting dormant review data and without overwriting the retained
review-database backup.

For the default deck, back up:

- `decks/deck.cosimo-deck`
- `decks/deck.reviews.sqlite3`, if it exists

For another deck such as `spanish.cosimo-deck`, back up the neighbouring
`spanish.reviews.sqlite3` file as well. Close Cosimo before copying or
restoring these files so SQLite is not in the middle of a write.

Restoring only the `.cosimo-deck` file restores the cards but loses scheduling
history. Restoring both files preserves the cards and their review history.
The optional `cosimo.ini` file can also be backed up to preserve language,
session settings, backup policy, the last opened deck, and the recent-decks
list.

When Cosimo opens a review database, it runs SQLite's quick integrity check
before applying schema setup or deck migrations. It also checks higher-level
consistency after opening, including stored rating and schedule values,
review-pass links, and active reversible cards whose responses have become
ambiguous. If either check fails, close Cosimo and restore the matching
`.reviews.sqlite3` file from an external backup, or fix the active deck if the
error is caused by a duplicated response on a reversible card.

To restore an automatic deck backup, close Cosimo and copy the chosen backup
over the active `.cosimo-deck` file. If you also need to recover scheduling
history, restore the matching `.reviews.sqlite3` file from an external backup
or from Cosimo's retained review-database backup.

Use `File -> Options -> Delete Old Backups` to keep only the newest automatic
backup for each original deck path. Cosimo asks for confirmation before deleting
or renumbering backup files.

## Localisation

The current message catalogue supports English, Spanish, and Galician. Runtime
messages and most control labels go through the localisation layer in
[src/localization.rs](src/localization.rs).

Language is chosen in this order:

- `COSIMO_LANGUAGE`, when set to a recognised code
- the persisted language in `cosimo.ini`
- the system locale
- English

`en`, `en-US`, and similar English codes resolve to English. `es`, `es-ES`,
`es-MX`, and similar Spanish codes resolve to Spanish. `gl`, `gl-ES`, and
similar Galician codes resolve to Galician. Unknown codes fall back to English.
On Windows, Cosimo reads the user's default locale through the platform locale
API. On other platforms, it checks `LC_ALL`, `LC_MESSAGES`, `LANG`, and
`LANGUAGE`.

## Build

The default build artifact is the GUI application.

```bash
cargo build
```

wxdragon and native wxWidgets pieces can take time to compile the first time.
Avoid `cargo clean` unless you actually need to throw away cached build output.

## Test

Fast library-only tests:

```bash
cargo test --lib --no-default-features
```

Check the GUI binary:

```bash
cargo check --bin cosimo
```

Fossil also runs pre-commit verification through
[tools/pre-commit-check.sh](tools/pre-commit-check.sh),
which executes both test commands before a normal commit.

## Run

```bash
cargo run
```

The application defaults to `decks/deck.cosimo-deck` beside the executable.
Review history is stored beside each deck, using the deck stem plus
`.reviews.sqlite3`; for example, `decks/spanish.cosimo-deck` uses
`decks/spanish.reviews.sqlite3`.

## Review Flow

1. On startup, review the ready-screen summary and the list of card prompts.
2. Add, edit, or remove cards before starting the pass.
3. Start the scheduled pass with `Alt-S`, or force-start the whole deck with
   `Alt-T`.
4. For each prompt, enter `1` through `4` for the pre-response guess, or press
   Space to reveal the response without recording a guess.
5. After the response is shown, enter `1` through `4` for recall feedback. If
   the card text needs correction, press `e` to edit it before rating recall.
6. Enter `0` during either rating phase to end the pass early.
7. Review the statistics and continue back to the ready screen.

## Accessibility Notes

The current review flow is built around native text and button controls:

- the ready screen exposes the card set through a native list box
- the ready screen supports keyboard access to start, force-start, and quit via
  mnemonics
- the prompt content is focusable and read by screen readers before rating
- Space can reveal the response without a pre-response rating
- the response content becomes focusable after the pre-response rating or
  direct reveal
- numeric keys activate ratings directly
- `e` opens the current card for editing after reveal and returns focus to the
  previous post-response control
- the statistics dialogue focuses the summary text first
- the card editor uses normal text controls for prompt and response editing
- informative messages are intentionally concise and avoid repeating focus
  information that the screen reader already announces

Accessibility regressions should be treated as blocking defects.

The beta accessibility acceptance check is recorded in
[docs/accessibility-acceptance.md](docs/accessibility-acceptance.md).

Known defect: on the target Windows screen-reader stack, tabbing or
shift-tabbing into the ready-screen prompt list can announce the selected item
twice. Arrow-key navigation inside the list, selection, edit, remove, and
review startup remain functional. This is currently treated as a known native
list accessibility defect rather than a release blocker.

## Version Control

This repository uses Fossil, not Git.

Useful commands in this checkout:

```bash
FOSSIL_HOME="$PWD" fossil status
FOSSIL_HOME="$PWD" fossil diff
FOSSIL_HOME="$PWD" fossil add path/to/file
FOSSIL_HOME="$PWD" fossil commit --nosync path/to/file -m "Describe the change"
```

`--nosync` is currently relevant because this checkout may try to autosync
against a readonly peer checkout and fail before the local commit completes.

This checkout also carries a Fossil `before-commit` hook in
[.fossil-settings/hooks](.fossil-settings/hooks).
If you absolutely have to bypass that hook, Fossil supports `--no-verify`.

If you add a new file such as an XRC resource, remember to `fossil add` it
before committing.
