SPEC v0.9: M12b and M12c outcomes (D-055 to D-058), U2 values, UX-9 (D-059, M12d)
- D-055 build-time copy of the keyword table, D-056 parseCategoryKeywords, D-057 enum declaration orders, D-058 E-7 example shows server_version 15 and 16 and its test compares them again. - D-051 fulfilled: §9.7 hex values from docs/ux/design-spec.md §2.3; design-spec.md binding, strings.csv the source of string resources. - D-059: ExpenseEditorOptions.frequentCategoryIds and CategoryRepository.deletable; new milestone M12d with PLAN-M12d and prompts/M12d.md; M7a-f depend on M6 and M12d. - suggestCategory readings (null when other is archived), §11.2 landed marks and the 2026-10-18 dry run, dev stack on schema 2, PLAN-M12b SQLite 3.51.x, design-spec §6 notes in PLAN-M6/M7c/M7f; HANDOFF rewritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
+6
-1
@@ -55,7 +55,12 @@ entry and the old one a strike-through plus a pointer. The spec is updated in th
|
||||
| D-048 | 2026-10-18 | Navigation stays at three destinations (Översikt, Statistik, Inställningar); §13.2 is binding. An "Aktivitet" feed (the other person's changes across accounts) was considered as a fourth tab and not taken for v1. | Owner's answer (UX-2). | SPEC §13.2 |
|
||||
| D-049 | 2026-10-18 | Category suggestion (§9.11 CS-1 to CS-7): for a new expense, while the category was not picked by hand in this editor session, the editor selects (1) the category used most often among expenses with the same normalised description, (2) else most often among expenses with the same first token, ties by the most recent expense in list order, then category id, (3) else the longest matching entry of the fixed keyword table `contracts/category-keywords.csv`, (4) else the AC-8.6 default. Recomputed on every description and account change; no marker; editing never changes a category. `ExpenseRepository.suggestCategory(accountId, description)` in `:data`; pure `suggestCategory(description, history, keywords, activeCategories, fallback, unicode: UnicodeText): CategoryId?` in `:domain` (Kotlin only) with `suggest_category.json`. `UnicodeText` (`nfc`, `isLetter(codePoint)`, `isDigit(codePoint)` meaning Nd) is an interface in `:domain` that `:data` binds with `java.text.Normalizer` and `Character`, because pure modules cannot use `java.*`; the records `SuggestionHistoryEntry(description, categoryId, expenseDate, createdAt)`, `CategoryKeyword(keyword, match, defaultKey: String)`, `ActiveCategory(id, defaultKey: String?)` and the enum `KeywordMatch` live in `:domain`, with default keys as strings. History ties: count, then the latest (`expense_date`, `created_at`), then the lower category id; code points walked by surrogate pairs; keywords rank by code-point length, then table order. As landed by M12a (`6b60ef7`). | Owner (UX-3): most expenses repeat the same shops; fewer taps in the ten-second flow (§13.1). Replay of the household's 1 775 Splitwise expenses: 79.7 % right versus 30.5 % for the AC-8.6 default alone; "most often" beats "most recent" by about one point (`docs/ux/category-suggestion.md`). | SPEC AC-8.6, §9.11, §13.3 (S-7), §14.2.4, §14.5.5, §14.5.6, §14.7, §14.8 |
|
||||
| D-050 | 2026-10-18 | S-1 has a required "Ditt namn" display-name field (1 to 40 code points, §9.6) on a first pairing, hidden in the "Para ihop telefonen igen" variant; a partner confirms it again on S-2 (AC-2.10). | UX-4: AC-2.4 sends a display name with the accept call, but S-1 listed no field for it. Owner OK. | SPEC AC-2.4, §13.3 (S-1) |
|
||||
| D-051 | 2026-10-18 | The §9.7 colour hex values are replaced by the muted Kalas values when U2 reports; the token names are fixed now, the two new ones being `slate` (insurance) and `amber` (fees), whose values are `TODO(U2)`. M6 starts only after the values have landed in §9.7. | UX-5: several provisional values (light orange, yellow, lime) fail contrast as icon colours on tinted containers; UX-8 needs two more tokens. | SPEC §9.7, §13.4 |
|
||||
| D-051 | 2026-10-18 | The §9.7 colour hex values are replaced by the muted Kalas values when U2 reports; the token names are fixed now, the two new ones being `slate` (insurance) and `amber` (fees), whose values are `TODO(U2)`. M6 starts only after the values have landed in §9.7. Fulfilled in SPEC v0.9 (2026-10-18): the §9.7 values are those of `docs/ux/design-spec.md` §2.3 (U2, landed `16c4d01`), `slate` `#5E2D4E` / `#B0719A`, `amber` `#937D63` / `#DFCFC0`, light `brown` `#6B5244`. | UX-5: several provisional values (light orange, yellow, lime) fail contrast as icon colours on tinted containers; UX-8 needs two more tokens. | SPEC §9.7, §13.4 |
|
||||
| D-052 | 2026-10-18 | Smaller UX rules: saving an expense shows "Utgiften sparades" without "Ångra" (S-7); an archived account's detail hides the add-expense FAB and keeps settling (S-5); the per-account settle-up keeps the direction swap and an editable amount, its one account row fixed (S-9); avatar initials use two colour tokens `avatar-1`, `avatar-2`, the slot a stable function of the user id (AC-4.5). The owner approved the Swedish wording "Ni är kvitt", "Gör upp", "Du lånade ut / Du lånade", "Inte inblandad" (AC-8.10; the copy lives in `docs/ux/strings.csv`). U2 renames the `strings.csv` keys to the feature prefixes of D-017. | UX-6, found during U1: an undo would be an audited create and delete that also notifies the partner; archived accounts take no new expenses (AC-6.4); §9.4 allows per-account settle-ups either way and AC-11.4 says the amount "defaults to". | SPEC AC-4.5, AC-8.10, §13.3 (S-5, S-7, S-9) |
|
||||
| D-053 | 2026-10-18 | Splitwise categories are mapped as finely as the fourteen categories allow: Rent, Mortgage, Hyra, Avbetalning/Amortering → `housing`; Insurance, Försäkringar → `insurance`; Childcare, Barnomsorg → `children`; Taxes, Skatter → `fees`; the Swedish labels El, Värme/gas, Vatten, Sophämtning (`utilities`) and Husdjur (`home`) added by analogy, to be checked against Splitwise (an unseen name only stays unmapped). The §10.8 table and `server/crates/kvitt-import/data/splitwise_categories.csv` change together (M12b). | UX-7 (owner, 2026-10-18): §10.8 collapsed Försäkringar (26 rows), Barnomsorg (73) and Skatter (19) into `other` and Hyra (106) and Avbetalning/Amortering (48) into `home`; "Hemförsäkring" must not end up in Övrigt. | SPEC §10.8 |
|
||||
| D-054 | 2026-10-18 | Fourteen default categories: `housing` Boende (`key`, `indigo`, 25), `insurance` Försäkringar (`shield`, `slate`, 45), `children` Barn (`child_care`, `lime`, 85), `fees` Avgifter & skatter (`account_balance`, `amber`, 95) join the ten; `home` keeps furniture, supplies, maintenance, electronics and services. Ids `01920000-0000-7000-8000-000000000011` to `…014`, `created_at` `2026-10-18T00:00:00.000Z`, `server_version` from the global sequence. Server schema 2 through migration 0002, which rebuilds `categories` (the v1 `CHECK` lists ten keys) under `PRAGMA defer_foreign_keys`, inserts the four rows and sets `schema_version` 2; its text is locked as `contracts/schema/migrations/0002_categories_v2.sql` (§14.1.1); `server-v1.sql` stays byte-locked. Icons 33 (`key`, `shield`, `account_balance`), colours 14, `DefaultCategoryKey` and `ColorToken` extended, OpenAPI enum, E-1 `schema_version` 2; the importer requires schema 2 (revises D-046's "1"). Room schema unchanged (rows arrive through sync). Carried out by milestone group M12 (M12a contracts, then M12b server and M12c Android in parallel; M6 and M7c after M12c). | UX-8 (owner, 2026-10-18): the household's history has these as large separate groups (Hyra + Amortering 154 rows, Barnomsorg 73, Försäkringar 26, Skatter 19) that were collapsed into Hem and Övrigt; separate categories make analytics and the suggestion meaningful. M3, M5 and M9 landed with ten defaults, so this is a contract change against `main`. | SPEC AC-7.2, §6.2, §9.7, §10.8, §11, §13.3 (S-15), §14.1, §14.1.1, §14.2.4, §14.3.3, §14.3.4 (E-1), §14.7, §14.8 |
|
||||
| D-055 | 2026-10-18 | The keyword table reaches the phone by a build-time copy: `:data:copyCategoryKeywords` and `:core:fakes:copyCategoryKeywords` copy `contracts/category-keywords.csv` into an AGP generated resource directory; a missing file fails the build. Packaged as the Java resource `se/hagstedt/kvitt/data/category-keywords.csv` (and `se/hagstedt/kvitt/fakes/category-keywords.csv` for the fakes, debug only); no committed copy. A `:data` test asserts byte identity with the contract file and the §14.8 rules. Supersedes the "byte-identical copy at `android/data/src/main/resources`" wording of v0.8. | M12c report (`e499107`): a committed copy can drift from the contract file; a build-time copy cannot. | SPEC §11.2 (M12c), §14.2.4, §14.7, §14.8; PLAN-M12c |
|
||||
| D-056 | 2026-10-18 | `:domain` exposes the pure `parseCategoryKeywords(csv: String): List<CategoryKeyword>`: header `keyword,match,default_key,source`, entries in file order, `IllegalArgumentException` on a malformed table; shared by `:data` and `:core:fakes`. | M12c report (`e499107`): two callers needed the same parser; `:domain` is the shared pure module. | SPEC §14.5.6 |
|
||||
| D-057 | 2026-10-18 | `DefaultCategoryKey` in `:core:model` is declared in AC-7.2 sort order. The Rust wire enum, the OpenAPI `DefaultCategoryKey` enum and the 0002 `CHECK` list the ten v1 keys, then `housing`, `insurance`, `children`, `fees`. Wire values are unaffected. | M12b (`2e2ebe7`) and M12c (`e499107`) reports: the declaration orders differ by side; enums compare as sets on the wire. | SPEC §14.2.4 |
|
||||
| D-058 | 2026-10-18 | The server's test harnesses seed the two users after the fourteen category seeds, so they have `server_version` 15 and 16. `contracts/examples/E-7-me/response.json` shows 15 and 16 (was 11 and 12, from schema 1's ten seeds), and the E-7 test compares `server_version` with the example again instead of treating it as volatile. | M12b report (`2e2ebe7`): migration 0002 moved the users' versions; the example should match what the server produces. | SPEC §14.3.5; `contracts/examples/E-7-me/response.json`, `server/crates/kvitt-server/tests/core_api/me.rs` |
|
||||
| D-059 | 2026-10-18 | UX-9 accepted as a contract change: `ExpenseEditorOptions.frequentCategoryIds: Map<AccountId, List<CategoryId>>` (per active account up to 5 active categories by use count in that account over the whole Room copy, ties by `sort_order`, unused ones left out; read once on open and on an account change) and `CategoryRepository.deletable(id): Flow<Boolean>` (false for a default or a category used by a non-deleted expense or template, AC-7.6; the server stays the authority), with the readings, UI text choice and fallbacks of §14.2.4 "Changes in v0.9". Implemented in `:core:model`, `:data` and `:core:fakes` by the new milestone M12d, run in parallel with M6; M7c and M7f consume it, and M7a to M7f depend on M6 and M12d. | U2 (`docs/ux/proposed-decisions.md` UX-9): S-7's `CategoryQuickRow` and S-15's category editor have binding states the UI contract did not carry. | SPEC §11.1, §11.2, §11.3, §14.2.4, §14.7; PLAN-M12d, PLAN-M7c, PLAN-M7f |
|
||||
|
||||
Reference in New Issue
Block a user