Paper lifecycle¶
Every paper in ALMa has two independent state dimensions. They are
stored as two columns on the papers table and they never overload
each other.
Membership axis¶
The papers.status column holds one of five mutually-exclusive
values:
| Value | Meaning | UI surfaces |
|---|---|---|
tracked |
ALMa knows about this paper but you haven't curated it. Default state for anything pulled from a monitor or a backfill. | Feed, Discovery candidates, Corpus Explorer |
inbox |
You sent this to yourself from another channel and haven't triaged it. A buffer between tracked and library — see Inbox. |
Home Inbox section |
library |
You have explicitly saved this paper. It is part of your curated collection. | Library tabs |
dismissed |
The global hide: don't surface this anywhere. Visibility only — it carries no opinion (see below). | Hidden everywhere by default; visible in Corpus Explorer |
removed |
You used to have this in your Library and chose to remove it. The row is preserved for provenance and as a negative signal. | Hidden by default; visible in Corpus Explorer |
Removal is a soft transition, not a hard delete ( why). The row stays so that Discovery knows you've explicitly rejected it and so that Insights counts stay coherent.
Colour is valence, membership is not (D6, amended 2026-07-26)¶
Four verbs move a paper, and they answer different questions. The word
"dismiss" used to answer all of them at once — it set status='dismissed',
stamped rating=1 and wrote a negative feedback event — so "I've dealt with
this" was indistinguishable from "this is bad".
| Verb | Axis | Scope | Writes |
|---|---|---|---|
save / like / love / dislike |
valence | global — one opinion per paper | rating + a feedback_events row |
dismiss |
resolution | the surface that raised it | that surface's row only. No rating, no event, no lens signal. |
defer |
membership | the Inbox | inbox → tracked. Nothing else. |
remove |
membership | global | status='removed' — still a negative (D3) |
Consequences worth knowing:
- Dismissing in one Discovery lens does not mute the paper in any other.
The cooldown is scoped
WHERE lens_id = ?; previously one dismiss suppressed the paper everywhere. status='dismissed'carries no valence. It is the global hide — a visibility choice. It is not insignal_valence.NEGATIVE_STATUSES, so tidying your surfaces cannot poison a paper's map colour.- Negative opinion is
dislike. "Bad and gone" is dislike plus dismiss: two verbs, composed deliberately. deferis not a verdict, it is the absence of one — which is why the Inbox X button cannot reusedismiss.
Reading axis¶
The papers.reading_status column holds one of four values
(NULL = none):
| Value | Meaning |
|---|---|
| (none) | Default. Reading workflow has nothing to say about this paper. |
reading |
You're actively reading it. |
done |
You've finished reading it. |
excluded |
You evaluated and decided not to read it. Distinct from dismissed (membership), which means "don't suggest". |
The reading axis is independent of membership. A paper in your Reading list does not have to be in your Library — you can queue something for reading while still deciding whether to keep it.
Every surface that changes it — Library's reading select, the Reading
list, Feed and Discovery's Queue button, undo, and a capture "to the
reading list" — goes through one writer,
paper_actions.set_reading_status. It validates the value (the retired
queued is accepted as reading), writes it on the paper-group root,
and bumps updated_at.
Why two axes¶
The most common UI failure in literature tools is conflating "I keep this paper" with "I have read this paper" with "I rate this paper highly". The three are independent:
- You can have an unread paper in your Library that you haven't rated yet.
- You can finish reading a paper without saving it.
- You can rate a paper without reading it (you've decided it looks promising).
Splitting the axes means each control in the UI has exactly one job.
The Reading status select sets reading_status. The Save button
sets status='library'. The star rating sets rating. None of them
touch the others.
Rating¶
The third small piece of state is papers.rating — an integer 0–5
that ALMa derives from the rating verb you used when saving:
| Verb | Resulting rating |
|---|---|
| Save (or Add) | 3 |
| Like | 4 |
| Love | 5 |
| Dislike | 1 |
- Ratings 1–2 are negative signals for the recommender.
- Rating 3 is neutral / minimally positive.
- Rating 4 is a +1 positive signal.
- Rating 5 is a +2 positive signal.
The rating is monotonic when re-saving: re-saving a Loved (5) paper with a plain Save will not downgrade it to 3. Only an explicit Dislike or a manual rating change can lower it.
How states transition¶
stateDiagram-v2
direction LR
[*] --> tracked: monitor / backfill
[*] --> inbox: capture (Slack / any channel)
tracked --> inbox: capture
inbox --> library: Save · Like · Love
inbox --> tracked: Defer (the X button)
tracked --> library: Save · Like · Love
tracked --> dismissed: Hide
library --> removed: Remove from Library
removed --> library: Re-save
removed --> inbox: capture (reconsidering)
dismissed --> library: Save (overrides)
dismissed --> inbox: capture (reconsidering)
library --> library: Like / Love / rating change
A capture never demotes a library paper — re-sending something you already
saved is reported as a duplicate and the row is left untouched.
Reading transitions are completely orthogonal to the diagram above.
What this means for the UI¶
- Feed shows
trackedpapers from your monitors. Saving a Feed paper transitions it tolibrary. Disliking it writes a negative signal but keeps it visible (Feed is chronological — it does not hide things). - Discovery shows
trackedcandidates the recommender thinks you haven't seen. Dismissing hides that recommendation in its lens without changing preference. Saving transitions tolibrary. - Home shows the Inbox — papers you sent yourself from
another channel. Triage moves them to
library, or the X button (defer) drops them back totrackedwriting no signal at all. - Library shows
librarypapers. Removing transitions toremoved. - Reading list shows papers with
reading_status='reading'— regardless of membership. - Corpus Explorer (Settings → Data & system) shows everything
including
dismissedandremoved, with the full state visible.
Where to read more¶
- Library — the curated surface
- Feed — the chronological inbox
- Discovery — the recommender
- Vision & philosophy — why the model is shaped this way
Repairing versions and components¶
Health and Settings share Reconcile paper groups. A published paper receives its preprint's saved state, reading state, ratings and notes; the preprint remains as a version pointer. Components donate no user state. Child records cannot independently affect Library counts, calibration or recommendation evaluation.
Title/year matches merge automatically only when each side has one plausible partner and both carry a DOI — a shared title and year alone is how two different papers become one. Ambiguous matches remain separate and are listed in Activity with the relevant paper IDs.
Preview before you repair. Health and Settings both offer a preview: it reads exactly what a pass would act on — relationships to repair, components to classify, merges ready, what the run limit would defer, and what is left for a person to judge — and writes nothing. Unattended auto-repair is unaffected.
The schema holds the rule too. papers.canonical_paper_id and
parent_paper_id cannot name their own row or a paper that is not in the
corpus; SQLite refuses the write. A database that already contains such a row
stays editable until Reconcile clears it, and Health counts it meanwhile.
Registered datasets know their parent. A DOI Crossref does not have is
looked up in DataCite, whose IsSupplementTo relation names the article a
deposited dataset, software release or supplement belongs to. It then becomes a
component of that paper like any other. The repair reports actual merges, failures and remaining
title matches. Its limit applies to new title matches; existing relationship
repair scans the corpus. Each group commits independently, so Library actions
remain available and a failed group does not undo successful repairs.