SPEC v0.7: M9 importer decisions (D-044 to D-046), category table, HANDOFF rewritten

D-044 adds nine Swedish Splitwise category names to the SPEC §10.8 table and
splitwise_categories.csv. D-045 records the reconciliation against the totals
rows; D-046 the importer CLI semantics and exit codes. M9 marked landed at
ab298ab, the M11 rehearsal recorded, server/README.md and prompts/README.md
updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-18 07:51:04 +02:00
parent 50339aef6d
commit 86e08a12cf
6 changed files with 61 additions and 43 deletions
+5 -2
View File
@@ -6,7 +6,7 @@ The Rust backend of Kvitt (SPEC §6.3): one Cargo workspace with three crates.
|---|---|---|
| `crates/kvitt-domain` | library, no I/O | Split, balance, allocation and settlement rules (SPEC §9.1, §9.3, §9.4, §14.5) and `next_occurrence_date` with the day clamping of §9.5. Passes every vector in `contracts/test-vectors/`. |
| `crates/kvitt-server` | binary `kvitt-server` plus `lib.rs` | Config, SQLite pool and migrations, HTTP API, auth, CLI. |
| `crates/kvitt-import` | binary `kvitt-import` | Splitwise importer (SPEC §10.8, milestone M9). In M2a it prints its usage and exits 2. |
| `crates/kvitt-import` | binary `kvitt-import` plus `lib.rs` | Splitwise importer, implemented per SPEC §10.8 (M9, D-044 to D-046): one CSV export per run into one account, in one transaction that commits only when every row is valid and the account balance reconciles with the file's totals rows. Exit codes: 0 ok, 1 database or file error, 2 usage, 3 cannot import, 4 reconciliation mismatch. Category table in `crates/kvitt-import/data/splitwise_categories.csv`. |
The Rust toolchain is pinned in `rust-toolchain.toml` (rustup installs it on first use); `Dockerfile` uses the same
version.
@@ -112,7 +112,7 @@ the wire contract makes `tests/openapi_contract.rs` fail against `contracts/open
`Period` (`YYYY-MM`, `FromStr`/`Display`, `next()`, `days()`, `clamped_date(day_of_month)`),
`next_candidate_period(start_period, end_period, last_generated_period) -> Result<Option<Period>, RecurrenceError>`
and `next_occurrence_date(&RecurrenceSchedule) -> Result<Option<String>, RecurrenceError>`.
* **Importer (M9):** `kvitt-import` already depends on `kvitt-domain` and `kvitt-server` (the library).
* **Importer (M9):** `kvitt-import` depends on `kvitt-domain` and `kvitt-server` (the library); it reuses the server's validation, row helpers and `SqlAuditWriter`, and never opens a database it would have to create or migrate (SPEC §10.8).
## Tests and the gate
@@ -135,6 +135,9 @@ From `server/`: `cargo fmt --check && cargo clippy --all-targets -- -D warnings
(an RSA key is generated per test; none is committed).
* `crates/kvitt-server/tests/scheduler_daily/` (M4): 06:00 and 04:00 across both DST changes, run at start, clock
jumps, catch-up through `generate_all_due`, paused and deleted templates skipped, 90-day pruning.
* `crates/kvitt-import/tests/import.rs` (M9): both header variants, split and settlement rules, `--fx`, the import key and
idempotent re-runs, reconciliation and its exit codes, dry run, the CLI, and the §10.8 category table against
`data/splitwise_categories.csv`; synthetic fixtures in `crates/kvitt-import/tests/fixtures/` only.
The M4 binaries reuse M3's harness (`tests/core_api/common.rs`) and `tests/sync_api/m4.rs` through `#[path]`. No `unwrap`/`expect` in non-test code (a crate-level `deny` enforces it under clippy).
@@ -53,8 +53,12 @@ Förbrukningsvaror,sv,home
Skötsel/underhåll,sv,home
Avbetalning/Amortering,sv,home
Hyra,sv,home
Tjänster,sv,home
Hem - Övrigt,sv,home
TV/telefon/internet,sv,utilities
Städning,sv,utilities
Verktyg - Övrigt,sv,utilities
Cykel,sv,transport
Buss/tåg,sv,transport
Bil,sv,transport
Bensin/bränsle,sv,transport
@@ -62,13 +66,18 @@ Parkering,sv,transport
Taxi,sv,transport
Transport - Övrigt,sv,transport
Hotell,sv,travel
Flyg,sv,travel
Spel,sv,entertainment
Musik,sv,entertainment
Filmer,sv,entertainment
Sport,sv,entertainment
Underhållning - Övrigt,sv,entertainment
Sjukvård/medicin,sv,health
Presenter,sv,shopping
Kläder,sv,shopping
Allmänt,sv,other
Barnomsorg,sv,other
Utbildning,sv,other
Försäkringar,sv,other
Skatter,sv,other
Livet - Övrigt,sv,other
1 splitwise_name language default_key
53 Skötsel/underhåll sv home
54 Avbetalning/Amortering sv home
55 Hyra sv home
56 Tjänster sv home
57 Hem - Övrigt sv home
58 TV/telefon/internet sv utilities
59 Städning sv utilities
60 Verktyg - Övrigt sv utilities
61 Cykel sv transport
62 Buss/tåg sv transport
63 Bil sv transport
64 Bensin/bränsle sv transport
66 Taxi sv transport
67 Transport - Övrigt sv transport
68 Hotell sv travel
69 Flyg sv travel
70 Spel sv entertainment
71 Musik sv entertainment
72 Filmer sv entertainment
73 Sport sv entertainment
74 Underhållning - Övrigt sv entertainment
75 Sjukvård/medicin sv health
76 Presenter sv shopping
77 Kläder sv shopping
78 Allmänt sv other
79 Barnomsorg sv other
80 Utbildning sv other
81 Försäkringar sv other
82 Skatter sv other
83 Livet - Övrigt sv other