Skip to content

Releases: VirInvictus/Colophon

## v2.6.0 (2026-09-15)

Choose a tag to compare

@github-actions github-actions released this 15 Sep 18:41

feat: the word-count axis ships (v2.6.0)

Version bump across every carrier with the release notes: per-book
words, words read, and true WPM behind the provided-EPUB gate;
lifetime words and the book-length distribution on the overview; the
Length and Pace personality traits. The granted zip dependency and
its vendored crates ride the train; the docs set (patchnotes, README,
CLAUDE.md, appdata, roadmap ticks) is current. 134 tests green.

## v2.5.0 (2026-09-15)

Choose a tag to compare

@github-actions github-actions released this 15 Sep 17:59

feat: page the years, recap by year, gather the annotations (v2.5.0)

The three GO'd features ship behind their spec definitions.

  • The year heatmap shows one calendar year (January through December,
    Monday-start, up to 53 weeks) with arrows stepping back through the
    past and forward toward today. The old rolling 52-week window
    silently clipped the oldest weeks the moment a year turned; that
    invisible regression is now a visible pager. Default: current year.
  • The recap card gains a per-year variant of the same composite (a
    finished work counts to its finish year, a started work to its first
    reading year), stepping from All time down through the years and
    back; the choice belongs to the card and never moves the global
    window. recap_for_year derives from the cached base, so paging is
    free.
  • An Annotations section on the overview lists every annotation from
    every provided sidecar, grouped by book in library order with
    entries in book order; a click opens the book's page. Hidden until a
    sidecar carries annotations, like everything user-provided.

Suite 126 green; clippy -D warnings, fmt clean.

## v2.4.1 (2026-09-15)

Choose a tag to compare

@VirInvictus VirInvictus released this 15 Sep 17:31

v2.4.1 (2026-09-15)

A hardening release from the final audit. No new features, and none of
your numbers move.

  • A corrupt or foreign database can no longer crash the app. The
    import dialog accepts any *.db, and a file carrying timestamps no
    calendar can name used to panic the day and hour charts when they
    rendered. Events outside an honest epoch window (1970 through 9999)
    are now dropped once at load, the same graceful treatment relative
    dates already had.
  • A bad import can no longer touch your good snapshot. Staged
    imports used to be validated by reading the book table only, so a
    database that opened but could not be fully loaded was promoted and
    failed afterwards, clobbering the snapshot it was supposed to be
    checked against. Validation now fully loads the staged copy first,
    and the promote-refuses path has an end-to-end test.
  • The year heatmap tooltip names books. The spec promised
    "time + pages + books"; the count was already computed and now shows.
  • The import path no longer stats the source on the UI thread. The
    source path can live on a network mount; the startup and
    mount-change probes moved off the main thread so a hung mount cannot
    freeze the window.
  • Read-through dates follow the reading day. A book finished just
    after midnight under a non-midnight day start showed one day late;
    completion rows now use the logical day.
  • The shortcuts window no longer documents a sidebar-resize
    accelerator that does not exist.
    Nothing ever bound F8, and GTK
    gives paned dividers no keyboard path; the false row is dropped.

Under the hood: the comment layer caught up with the post-D1 data
path, CLAUDE.md synced with the 2026-09-12 decisions, and the spec,
README, and RESEARCH records had their truth fixes (the junk threshold
is fixed, not configurable; Tier B renumbered 10-17; the default theme
is Follow-system, not Dragon). An advisory gate (cargo-deny) joined
CI, a SECURITY policy and a justfile landed, the MSRV is declared
(1.85), CI actions are SHA-pinned with a versioned Fedora container,
releases are now cut automatically from tags, and the approved
removals shipped (the unused directory-scan API and all_events;
rescaled_events stays as the test oracle).

Suite 124 green across the workspace; clippy -D warnings, fmt clean.

## v2.4.0 (2026-09-06)

Choose a tag to compare

@VirInvictus VirInvictus released this 15 Sep 16:05

v2.4.0 (2026-09-06)

Your margins, readable.

  • The annotations browser. A book whose sidecar you have provided now
    lists its highlights, notes, and bookmarks on the book page, in book
    order. Each entry names what it is and where it falls (as a percent of
    the book), shows the device-captured excerpt wrapped to full width, and
    your own note beneath it in the dim style; bookmarks, which carry no
    text, list as their position alone. KOReader stores annotations in the
    order you made them, so Colophon orders them by where they fall in the
    book instead. Books without a provided sidecar show nothing new, as
    always. The activity-strip markers and the counts on the stat cards are
    unchanged.

Suite 119 green across the workspace; clippy -D warnings and fmt clean.

## v2.3.1 (2026-09-06)

Choose a tag to compare

@VirInvictus VirInvictus released this 15 Sep 16:05

v2.3.1 (2026-09-06)

  • The Flatpak build is offline-capable. Every crate dependency is now
    vendored into the build (generated-sources.json, generated from
    Cargo.lock), so the build sandbox needs no network access and the
    --share=network build-time escape hatch is gone. Verified with a real
    local flatpak-builder run: the app builds and runs under the GNOME 50
    runtime with no network. This closes the one gap between the manifest and
    a Flathub submission (the app-id question is a separate, workspace-wide
    decision). Nothing about the app itself changed.

Suite 117 green across the workspace; clippy -D warnings and fmt clean.

## v2.3.0 (2026-09-06)

Choose a tag to compare

@VirInvictus VirInvictus released this 15 Sep 16:05

v2.3.0 (2026-09-06)

For night owls: the reading day can start when yours does.

  • A configurable day start. Preferences gains a "Reading day" group:
    pick the minute past midnight your reading day begins (arrows step 30
    minutes, or type HH:MM; the default 00:00 is the plain calendar day).
    With a 04:00 day start, reading done between midnight and 04:00 counts
    toward the previous day, so one late-night sitting reads as one day
    everywhere a day appears: daily totals, streaks, the year heatmap,
    monthly bars, speed buckets, the 30/90/365-day windows, and every
    displayed date, including "today" in the streak rules. The change
    applies live. What never moves: the clock hours. The when-do-I-read
    heatmap still shows the real hour you read, and speed by hour and
    session starts stay on the clock.

Suite 117 green across the workspace; clippy -D warnings and fmt clean.

# v2.2.0 (2026-09-04)

Choose a tag to compare

@VirInvictus VirInvictus released this 15 Sep 16:05

v2.2.0 (2026-09-04)

Data-quality fixes from the 2026-09-04 audit (D1-D3), each with its spec
amendment as the first step.

  • D1 — merged books no longer conflate pagination axes. page_totals
    and rescaled_events rescale every merged row's events onto the
    canonical row's page count in SQL (the canonical page count is bound as
    a parameter; the per-row book JOIN is gone). Previously the page_stat
    view rescaled each row against its own pages, so merged rows recorded
    under different paginations summed positions from two different axes into
    one bucket. Zero-total_pages rows drop out exactly as they did in the
    view (the division yields NULL and the fan-out predicate rejects them).
  • D2 — an unknown page count hides page-derived stats instead of
    printing confident zeros.
    Book::pages is now Option<i64>; a book
    whose page count KOReader never learned hides unique pages, rescaled
    positions, completions, capped totals, and the per-page strip, while its
    time-derived stats keep rendering. unique_pages_read and
    rescaled_last_page keep i64 signatures; the Option is unwrapped at
    the loader boundary.
  • D3 — library-wide aggregations key on the full work identity.
    forgotten_books, finished_timeline, and the Recap's started/finished
    sets now key on library::group_key's (title, authors) instead of the
    trimmed title alone, so two different works sharing a title no longer
    collide (and the Recap's completion rate stops undercounting). The
    title-keyed sites inside series/author buckets are correct and
    untouched; the Jingo one-work-two-files case has a test proving the fix
    doesn't overshoot.

Suite 112 green across the workspace; clippy -D warnings, fmt, and
pyright strict all clean.