feat(store): draft states and discards are journaled, posted_seq is kept (P4)

Accounting reason: a draft that waits on its receipt, and one thrown
away, are facts about the books' working papers that must survive a
restart and replay identically, or a discarded draft would come back and
hold its period open. entry.draft_state_set and entry.draft_discarded are
drafts_v2's (an older version stops at the declaration instead of
misreading them); no figure moves. Schema 19 (taken at merge as the next
after the current last): entries.posted_seq, and a draft_states table
(drafts are not rows of entries, so the plan's entries.draft_state column
has nowhere to live). posted_seq is the journal line that posted each
entry (entry.posted, entry.reversed, the line that closed a period or
posted a schedule month), identical live and on replay.

8.0.6: a hand-written line of each new shape in
books_written_under_older_rules_still_open; fixture old-books/p4_before
written by 25b52580 (hand entries posted late, a reversal, a document, a
schedule month, a recurring draft, open drafts, a close) opens to the
same figures (serialized entries omit a building state, so no golden
moved); drafts_v2_is_its_own_feature; the fuzzer and GUI journal know the
types.

Tests: draft_states_replay_and_project, drafts_v2_waits_for_the_upgrade,
posted_seq_is_the_posting_lines_seq, an_older_version_stops_at_the_draft_events.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
swaitsandClaude Fable 5.1 committed 2026-10-29 13:55:17 -06:00
1 parent be8bcf340e
commit 28d46332e4
18 files changed
+1455 -24

No files matched your search

+18 -1
View File
@@ -5,7 +5,7 @@
//! is the current version.
/// Current schema version.
pub const SCHEMA_VERSION: u32 = 18;
pub const SCHEMA_VERSION: u32 = 19;
/// Migrations, in order. `MIGRATIONS[i]` migrates from version `i` to `i+1`.
pub const MIGRATIONS: &[&str] = &[
@@ -468,5 +468,22 @@ CREATE TABLE IF NOT EXISTS annotations(
seq INTEGER NOT NULL
);
ALTER TABLE attachments ADD COLUMN duplicate_of INTEGER NULL;
"#,
r#"
-- v19: draft states and posting order (plan P4, `drafts_v2`). Drafts are
-- not rows of `entries` (they never touch the projection until posted),
-- so a draft's state has a table of its own: one row per draft awaiting
-- its evidence (a draft being built is the default and has no row), gone
-- when the draft posts or is discarded. `posted_seq` is the journal line
-- (`entry.posted` or `entry.reversed`) that posted the entry: what the
-- digest's `since_seq` reads. Old rows are never migrated in place: the
-- database file is named for its schema, so a v19 file is built from the
-- journal.
ALTER TABLE entries ADD COLUMN posted_seq INTEGER NULL;
CREATE TABLE IF NOT EXISTS draft_states(
entry_id INTEGER PRIMARY KEY,
state TEXT NOT NULL,
note TEXT NULL
);
"#,
];