SPEC v0.18: D-109 to D-117; validation reports; HANDOFF, prompts
Build Kvitt images / build (push) Failing after 1m24s

- D-109 S-16 lost version read-only (Rejection.lost: RejectedVersion), D-110 S-22 versions from /health
  (AboutState.schemaVersion), D-111 SettlementRepository nullable start/recompute, D-112 E-17 retry,
  D-113 invite-partner and the push sent line, D-114 picture 16 MP / 64 MB and fcm_token 512 limits,
  D-115 rate-limit token acceptance (revises D-032), D-116 private notifications (AC-13.9) and L-6 as
  built (OQ-6), D-117 infra security (Caddy log redaction and headers, non-root Caddy, dev secret,
  digest record, key form).
- §10.5.2 quotes infra/pi/Caddyfile at 7fb86f5; §10.4 invite-partner row; §11.2 M12f row; §11.3 server
  gap pass, server overhaul, infra notes; new §11.4 validation reports; §14.7 server tree; strings.csv
  562 rows; localeFilters, work-testing, harness fix, APK 10.0 MB.
- docs/validation/ac-coverage.md and security-review.md committed verbatim from the reports.
- Commit hashes in SPEC, decisions, HANDOFF and prompts/README remapped to the rewritten history (18c527f).
- design-spec: S-16 lost-version dialog, S-22 "(schema <n>)", the S-1 rationale mention dropped.

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 22:48:15 +02:00
parent b985ce969d
commit 48fe119ae1
7 changed files with 864 additions and 232 deletions
+3 -3
View File
@@ -666,7 +666,7 @@ Each screen: layout top to bottom, the **binding states** (exactly the frames of
* Code typing: uppercase, hyphens inserted after 4 and 8, normalised per §8.3; "Para ihop" enabled when the code has 12 characters, the name is non-blank (first pairing) and the server is a valid URL. IME `Next` from code to name, `Done` on the name runs "Para ihop".
* "Klistra in": reads the clipboard; a 12-character code or an invite link (`kvitt://invite?…` or `https://…/i/<CODE>`) fills code (and server).
* Other errors, all inline under the field at fault, button enabled again: network "Kunde inte nå servern. Kontrollera adressen och anslutningen." (under the server row, which expands); `rate_limited` "För många försök. Vänta en stund och försök igen." (under the code); `http://` in release (AC-2.8) "Adressen måste börja med https://" (server). Offline: the button stays enabled and gives the network error (pairing never queues).
* Success: `pair(serverUrl, code, displayName, deviceName = Build.MODEL)` → partner pairing goes to S-2 (AC-2.10), otherwise S-4 in its loading state; after the first full sync the system notification-permission prompt (AC-2.9), preceded by nothing (the rationale string `home_notification_rationale` is used only if Android asks for a rationale).
* Success: `pair(serverUrl, code, displayName, deviceName = Build.MODEL)` → partner pairing goes to S-2 (AC-2.10), otherwise S-4 in its loading state; after the first full sync the system notification-permission prompt (AC-2.9), preceded by nothing (no rationale screen).
**TalkBack**: the paste button reads its text "Klistra in" (`onboarding_code_paste`); the code field reads the value group by group; the server row "Serveradress, https://icehack.asuscomm.com:8443, dubbeltryck för att ändra"; errors are announced (live region assertive).
@@ -1042,7 +1042,7 @@ Full screen (§13.2), works offline (AC-8.2). The flow and the category rule are
| `S-16-sync-clock` | variant clock skew | clock banner first; status "Synkad för 2 h sedan" / "Senaste försöket nekades: klockan" with `sync_problem`; pending rows; no rejection list |
| `S-16-sync-empty` | empty | status card "Allt är synkat" (`home_sync_status_all_synced`) over "Senast lyckade synk 13:59"; "Synka nu"; no pending or rejection sections |
**Interactions**: "Öppna" opens the entity's current version (S-8 / S-10; deleted or missing states apply); "Ta bort från listan" → `dismiss` (works offline). The rows update live while a sync runs.
**Interactions**: "Öppna" opens the lost version read-only (D-109) when `Rejection.lost` is set: a dialog with "Din version" (headline-small, `home_sync_lost_title`), "Så här såg det ut på telefonen. Det sparades inte och kan inte ändras här." (body-medium muted, `home_sync_lost_body`), the ledger row it would have been (`ExpenseRow` / `SettlementRow` with a null `onClick`, so it is not tappable), `FactRow`s for account, payer, split and notes where present, the badge "Du tog bort den här" (`delete`, `home_sync_lost_deleted`) with the facts at the deleted alpha when the refused change was a deletion, and "Visa nuvarande version" (`home_sync_lost_show_current`), which opens the current version (S-8 / S-10; deleted or missing states apply); without `lost` (unreadable payload, or its category or a user is not on the phone) "Öppna" opens the current version directly. "Ta bort från listan" → `dismiss` (works offline). The rows update live while a sync runs.
**TalkBack**: status card one node; rejection card one node plus its two buttons, read with their visible text ("Öppna", "Ta bort från listan", `home_sync_status_dismiss`).
@@ -1132,7 +1132,7 @@ Not a screen: the `UpdateBanner` on S-4 (and S-22) and one dialog.
### S-22 About (`:feature:settings`)
**Layout** (app bar: back, "Om Kvitt"; column gap 10): centred app mark 96 (Sunny, `primary`, `receipt_long` 48), "Kvitt 1.1 (11)" (headline-medium), "Delade utgifter för två" (body-medium muted); `UpdateBanner` when an update is available; group of `FactRow`s: Server (`dns`, URL wraps), Serverversion (`memory`, "1.1.0" or "Okänd" when `/health` failed); no open-source licences row (OQ-5, D-099); "Sök efter uppdatering" (tonal medium, `system_update`, centred; hidden in debug builds, AC-16.5).
**Layout** (app bar: back, "Om Kvitt"; column gap 10): centred app mark 96 (Sunny, `primary`, `receipt_long` 48), "Kvitt 1.1 (11)" (headline-medium), "Delade utgifter för två" (body-medium muted); `UpdateBanner` when an update is available; group of `FactRow`s: Server (`dns`, URL wraps), Serverversion (`memory`, "1.1.0 (schema 3)" from `/health` when S-22 opens online, `settings_about_server_version_schema`; offline or when `/health` fails the last response's server-version header without the schema, "1.1.0", or "Okänd" when none is known; D-110); no open-source licences row (OQ-5, D-099); "Sök efter uppdatering" (tonal medium, `system_update`, centred; hidden in debug builds, AC-16.5).
**States**