- 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
11 KiB
PLAN-M6: Design system
1. Goal
Implement :core:design from the approved docs/ux/design-spec.md: theme, colour and category tokens, typography, shapes, spacing, shared components, the three analytics charts, and MoneyFormatter/DateFormatter per §9.8. Every component has screenshot tests in light and dark, Swedish and English, so the feature agents compose screens without inventing visuals.
2. Read first
docs/ux/design-spec.md(tokens, component inventory; the screen sections only to know which components are needed).docs/ux/strings.csv(shared strings) anddocs/ux/screens/(reference renders).- SPEC §6.2 Android app (rows UI, Charts, Tests;
:core:designrow of the module table). - SPEC §9.7 Icon and colour tokens, with the hex values as updated by the spec change from U2's proposal; that change lands before M6 starts (§11.1). §9.8 Formatting, §9.2 and §9.3 (wording the components render).
- SPEC §13.1 Context (accessibility, font scale, tabular figures), §13.2 Navigation model.
- SPEC §4 AC-4.5 (initials avatar), FR-14 AC-14.6, AC-14.10 (charts), FR-19 Localisation and formatting.
- SPEC §11.2 (row M6), §11.3, §14.7 (including the Strings paragraph), §6.2 "Feature convention (D-017)";
docs/decisions.mdD-017, D-019, D-020. - Files:
android/core/model/**,android/build-logic/**,android/gradle/libs.versions.toml,docs/decisions.md,CLAUDE.md(BUILD AND VERIFY: Screenshots; ARCHITECTURE RULES; ANTI-PATTERNS).
3. Already established
- Compose, Material 3, Material 3 Expressive components where stable; follows system light/dark (§6.2, §13.1).
- Charts: Vico; if Vico's current release cannot draw a stacked bar chart with Material 3 theming, hand-roll the three charts with Compose
Canvasin:core:design(§6.2). - Shared components named in §6.2: money text, avatar, category chip, balance header, charts; the ledger rows (expense row per AC-8.10 and settlement row per AC-11.7, used by S-5, S-12 and the pending list of S-16) and the expense editor fields (amount entry, description, account picker, category grid, date, payer toggle, split section with live preview, notes, used by S-7 and S-19) (D-019); plus
MoneyFormatter,DateFormatter(§6.2). The full inventory is the design spec's. - Typography uses the Material 3 default typeface; no font file is bundled and no licence step is needed (D-020).
- Shared strings in
:core:designinclude the notification copy of §13.3 and the channel name "Activity"/"Aktivitet" of §14.6, which:appuses; their keys never start with a feature name (D-017). - Money: sv
1 234,50 kr(U+00A0 thousands and beforekr, comma decimal, two decimals); other localesSEK 1,234.50(U+00A0 afterSEK); never a minus sign; dates in lists3 okt./3 Oct, with year when not the current year; detaillördag 3 oktober 2026/Saturday, 3 October 2026; times14:02; relative "last synced" per §9.8 (§9.8). Formatting lives in:core:design, never in:domain(§9.8). - Colour token names are the 14 of §9.7 (
ColorToken,slateandamberadded by D-054, hex values from U2 per D-051); icon tokens the 33 of §9.7 (CategoryIcons.ALL); fourteen default categories (AC-7.2), whose localised default names:core:designholds as shared strings (§9.7, §14.2.4, D-054). Direction "Kalas", muted (D-047). M12c must have landed (§11.2). - Initials: first letter of the first two words, uppercase, on a colour derived from the user id (AC-4.5).
- Accessibility: 48 dp targets, 4.5:1 contrast, TalkBack labels, reflow at 200 % (§13.1).
- No hard-coded colours, sizes or strings in features: tokens come from one design file; shared strings live in
:core:designwith keys fromdocs/ux/strings.csv; lintMissingTranslationis an error in this module (CLAUDE.md, §14.7 Strings, D-017). - M2b created the module shell (build file, manifest, empty string files); M6 owns it and fills it in (D-004).
- Screenshot goldens are committed; open every changed PNG before committing (CLAUDE.md).
:core:designdepends only on:core:model(§6.2).- Design-spec open points (
docs/ux/design-spec.md§6, SPEC v0.9): (1) System font on One UI:FontFamily.Defaultmay resolve to a One UI font instead of Roboto; check on the owner's S26 that amounts stay tabular (tabular figures) and weights 500, 600 and 700 are distinct, and report it (D-020 stands either way). (2) Material 3 Expressive API status: check every Expressive API of design-spec §3.1 against the Material 3 release pinned inandroid/gradle/libs.versions.toml; any that is not usable (not in the pinned release, or experimental without a stable path) takes its listed stable fallback without a design change; list each with its outcome in the report. (3) S-19 has no category suggestion (CS-1);CategoryQuickRowmust work without one. - The §9.7 hex values are in SPEC v0.9 (from design-spec §2.3; D-051 fulfilled);
design-spec.md§2 and §3 andstrings.csvare the sources (§13.4). M6 started 2026-10-18.CategoryQuickRowtakes its list from the caller:ExpenseEditorOptions.frequentCategoryIds(D-059) is added by M12d in parallel; the component must not depend on it existing. - Avatars (v0.5, §14.2.4 readings):
:dataalways loads pictures at size 512 (E-11); the 128 variant is unused. If the avatar component needs the small size, ask the orchestrator for a size parameter (a contract request on:core:modeland:data).
4. Owned paths
From SPEC §14.7, verbatim: android/core/design/** (owner M6; after landing: "M7x may not edit; requests go through the orchestrator").
Also from §14.7: "later plans may add catalog entries and module includes (rebase resolves)" for android/gradle/** and android/settings.gradle.kts.
Edit nothing outside these paths; a needed change elsewhere is a contract request to the orchestrator.
Never edit SPEC.md or docs/decisions.md: put proposed decision entries (for example the chart choice) in the report.
Resolved open points (SPEC v0.3):
- (a) M6 builds the ledger rows and the expense editor fields in
:core:design(D-019). - (b) No font is bundled; the app uses the Material 3 default typeface (D-020).
- (c) The §9.7 colour change lands in the spec before M6 starts (§11.1); confirm it in step 2.
5. Deliverables
android/core/design/build.gradle.kts: dependencies (:core:model, Compose, Material 3, Vico if used, Coil for avatars)..../design/theme/**:KvittTheme, colour schemes light and dark, category colour tokens mapped fromColorToken, typography (with tabular figures for amounts), shapes, spacing scale, elevation, motion tokens from the design spec..../design/component/**: every component of the design spec's inventory (at least money text, avatar with initials, category chip and icon, balance header in three states, sync line, update banner, empty and error blocks, "Needs connection" hint, the ledger rows and the expense editor fields of D-019)..../design/chart/**: stacked bars over time, category breakdown bars, account breakdown bars..../design/format/MoneyFormatter.kt,DateFormatter.kt: §9.8, with unit tests for every example in §9.8.android/core/design/src/main/res/values/strings.xml,values-sv/strings.xml: shared strings fromdocs/ux/strings.csv, including the notification copy and channel name.- Screenshot tests for every component in light and dark, Swedish and English, plus 200 % font scale for the balance header and money text; committed goldens.
- The proposed decision text for the chart choice (Vico or Canvas), in the report.
6. Steps
- Worktree. From the main checkout
/Users/jhag/projects/kvitt:git worktree add .claude/worktrees/agent-m6 -b agent-m6 main, then in.claude/worktrees/agent-m6:git reset --hard main. Copyandroid/local.propertiesfrom the main checkout (addsdk.dirif missing; never overwrite or commit). Runtools/install-git-hooks.sh. - Read §2 in order. Confirm U2's design spec is on
mainand approved (start prompt), M2b has landed, and the §9.7 hex change is in SPEC; otherwise stop and report. - Run
python3 tools/dependency-report/latest.py; record the lines. Versions: Vico latest stable (official Vico documentation and releases); check whether it draws a stacked bar chart with Material 3 theming; record the finding and the decision (Vico or Canvas). Confirm Material 3 Expressive component stability from developer.android.com. Record versions. - Formatters test-first from the §9.8 examples (both languages, current-year and other-year dates, relative times).
- Theme and tokens from the design spec; contrast check of every text/surface pair the spec lists (unit test computing ratios).
- Components one by one, each with previews (real Swedish and English data from the design spec, no placeholder text) and screenshot tests in light/dark × sv/en.
- Charts with screenshot tests (empty, one group, many groups, week granularity).
- Record goldens; open every PNG; post the paths for the owner's look (§8).
- Run the gate (§7). Commit on
agent-m6,git rebase main, rerun the gate. Never merge, push or remove the worktree.
7. Gate
From SPEC §11.2, verbatim: "Android gate".
Command, from android/: PATH=/opt/homebrew/opt/openjdk@25/bin:$PATH ../tools/gradle-serial.sh check.
Green means: BUILD SUCCESSFUL in this session with the screenshot verification task for :core:design run and passing; formatter tests in fresh XML, 0 failures; the report lists one screenshot per component × light/dark × sv/en.
8. HUMAN steps
From SPEC §11.2, verbatim: "Look at the component screenshots the agent opens and posts (yes/no)". Where in the flow: after step 8, before committing the final goldens; the orchestrator shows the owner the PNG paths the agent lists and relays yes/no. A "no" with a comment goes back to the agent before the gate run.
9. Out of scope
- Feature screens and their ViewModels (M7a to M7f); feature strings.
- Navigation,
:app(M8);:data(M5). - Changing token names, enums or
:core:model(contract change). - Changing the design spec (U2's file); disagreements go in the report.
10. Report
- Branch
agent-m6, head commit hash after rebasing onmain. - Gate output: BUILD line, actionable tasks line, screenshot task result, test counts from fresh XML.
- Versions chosen with sources; dependency-report lines; chart decision (Vico or Canvas) with the reason, as decisions text.
- Component list with screenshot paths (for the owner's look) and the owner's yes/no.
- How resolved points (a) to (c) were applied; the public API of the ledger rows and editor fields (for M7b, M7c, M7e, M7f).
- Proposed decision entries (never written to
SPEC.mdordocs/decisions.mdby this agent) orTODO(spec)occurrences. - Contract requests, open questions, spec gaps (with section numbers).
11. Numbering
Decision ids, spec version and schema version are assigned by the orchestrator in the start prompt; use TODO(spec) if none was given.