SPEC v0.18: D-109 to D-117; validation reports; HANDOFF, prompts
Build Kvitt images / build (push) Failing after 1m24s
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:
+50
-37
@@ -3,62 +3,75 @@
|
||||
Living document, rewritten in place (never a second copy). A new orchestrator session reads CLAUDE.md, then this.
|
||||
|
||||
## 1. Where things stand
|
||||
- `main` at `4755fe0` (chips cleanup) plus the SPEC v0.17 docs commit from `agent-docs-v017` once it lands. History: `5e1be38` plans and prompts, `c885aba` M2c-dev, `76ee957` SPEC v0.3, `fad6fc9` M2b, `fdf2093` M2a, `040bf41` SPEC v0.4, `503cee5` M3, `c28c52b` M5, `982451d` SPEC v0.5, `bd6f10a` M4, `23a2f1e` SPEC v0.6, `ab298ab` M9, `e8ee518` SPEC v0.7, `6b60ef7` M12a, `7fb9f6f` SPEC v0.8, `e499107` M12c, `2e2ebe7` M12b, `d452fa6` UX Kalas categories and tokens, `16c4d01` UX sprint U2, `45eecd1` SPEC v0.9, `bdba9d3` M12d, `3080804` M6, `7bd0aa1` SPEC v0.10, `72f21b2` app debug fakes bindings (temporary, deleted by M8), `e6ad858` app release wiring of `:data` (pre-M8), `b9b061a` M7a, `6ac711d` M7e, `082b8dc` M7d, `31760f9` M7b, `1e42f76` M7c, `a54eb7c` M7f, `3a1bd14` M6b, `d504004` SPEC v0.11, `34a2590` M7g, `369e516` and `00a14a3` M8, `cf8ef45` SPEC v0.12, `1470a2f` M12e contract pass, `90505a8` M12e launcher icon, `03b7184` SPEC v0.13, `2b4e21c` Vico catalog entries removed (D-063), `c694f78` server FCM target in `fid` (D-096), `1e404cc` Pi image arm64 check (`docs/spikes/pi-image-arm64.md`), `fd60170` SPEC v0.14, `f0575d3` M8b UI fixes from the first phone test, `09f474f` `FcmMessageBody.fid` in `:data` (D-096 follow-up), `e7d963a` SPEC v0.15, `b481fab` M8c goldens at 1x in three variants (D-098), `64f5706` M8c S-22 licences row removed (D-099), `7c453d8` every PNG through oxipng, `57f984f` R8 release build, `3c68594` M8d editor rows (D-102), `3a3720b` SPEC v0.16, `5e027df` M2c-pi Pi bundle (D-103 to D-106), `15397e4` M8e S-19 option rows (D-107), `965bb5d` server Dockerfile `CARGO_BUILD_JOBS` argument, `ed1b130` M8f instant navigation (D-108), `4755fe0` unused editor chips removed.
|
||||
- Landed: M0 spec, M1 contracts and vectors (`c6df2ab`), M2a (`fdf2093`), M2b (`fad6fc9`), M2c-dev (`c885aba`), M3 (`503cee5`), M4 (`bd6f10a`), M5 (`c28c52b`), M9 (`ab298ab`), M12a (`6b60ef7`), M12b (`2e2ebe7`), M12c (`e499107`), U1 and U2 (`16c4d01`, owner approved), M12d (`bdba9d3`), M6 (`3080804`), M7a to M7f, M6b (`3a1bd14`), SPEC v0.11 (`d504004`, D-069 to D-080), M7g feature cleanups (`34a2590`), M8 app integration (`369e516` + `00a14a3`, landed 2026-10-18, gate green: BUILD SUCCESSFUL, 710 actionable tasks), SPEC v0.12 (`cf8ef45`, D-081 to D-085), M12e contract pass (`1470a2f` + `90505a8`, landed 2026-10-18; gates green: Android BUILD SUCCESSFUL, 710 actionable tasks, 906 tests; cargo 253 tests, OpenAPI equality, vectors and migration byte-identity green), SPEC v0.13 (`03b7184`, D-086 to D-095), Vico removal (`2b4e21c`), FCM `fid` target (`c694f78`, D-096), Pi image arm64 check (`1e404cc`: C stage, CA roots and an OAuth plus FCM call from the arm64 image confirmed on the Mac; running on the Pi stays M2c-pi's), SPEC v0.14 (`fd60170`, D-096), M8 on-phone test (2026-10-18, passed), M8b (`f0575d3`, D-097), `FcmMessageBody.fid` (`09f474f`), SPEC v0.15 (`e7d963a`, D-097, D-100, D-101); landed today after v0.15: M8c (`b481fab`, `64f5706`, `7c453d8`; D-098, D-099), the R8 release build (`57f984f`), M8d (`3c68594`, D-102); SPEC v0.16 (`3a3720b`); then the M2c-pi bundle (`5e027df`, D-103 to D-106), M8e (`15397e4`, D-107), the Dockerfile `CARGO_BUILD_JOBS` argument (`965bb5d`), M8f (`ed1b130`, D-108) and the chips cleanup (`4755fe0`).
|
||||
- M2c-pi bundle outcome (SPEC v0.17): `infra/pi/` with `compose.yaml`, `.env.example`, `Caddyfile`, `install.sh`, `deploy.sh <tag> [--skip-backup]` (backup before every deploy, `/opt/kvitt/previous-tag`), `bootstrap.sh`, `backup-now.sh`, `install-apk.sh` (D-103); images `gitea.lan/jacobh2/kvitt-server|kvitt-cert-sync|kvitt-backup`, Gitea workflow `.gitea/workflows/build-images.yaml` (runner `host`, secret `kvitt_cicd`, tags `v1.0.N` + `latest`, `CARGO_BUILD_JOBS=1`), `infra/build-images.sh` as Mac fallback, supercronic instead of crond (D-104); `backup` uid 10001, `rclone.conf` owned 10001 (D-105); cert-sync tar stream for both key variants, backup confirm-then-delete (D-106). Gate at landing: shellcheck clean on 18 scripts, compose config valid, cert-sync arm64 image builds; rehearsed on the Mac with Podman (cert-sync install, renew, skip, refuse; Caddy reload; `Authorization` redacted; TLS 1.1 refused; backup upload, `lsf` confirmation, delete after confirm, failed-upload retry; healthcheck red at 26 h; APK prune keeps 5). Not verifiable from the Mac: the add-on's `authorized_keys` options, the Gitea workflow run, pulls from `gitea.lan`, the router forward, Drive, real Docker compose.
|
||||
- M8e, M8f and cleanup outcome (SPEC v0.17): S-19's account, payer and split are three fixed `EditorOptionRows` (D-107); navigation is instant, no `NavHost` transitions (D-108); `AccountChip`, `PayerChip`, `SplitChip` removed (`4755fe0`), S-9 keeps `DateChip` in `EditorChipRow`.
|
||||
- M8 outcome (recorded in SPEC v0.12 as D-081 to D-085): both variants bind `:data` through `di/AppDataModule.kt`, debug fakes module gone (D-081, revises D-041); debug network security config allows cleartext everywhere, the AC-2.8 limit is enforced in `SessionRepositoryImpl.normaliseServerUrl`, pinned-root config behind `kvitt.tls.pinnedRoot` (D-082); FCM registration by Firebase Installation ID, firebase-messaging 26.0.0, no server change (D-083); invite links ignored while paired (D-084); generic-notification, deletion and `sync_batch` taps open Home, push in an expedited WorkManager job (D-085).
|
||||
- M8 end-to-end test (2026-10-18, dev server, owner's S26): pairing with the bootstrap code OK; a scripted partner joined through a second admin device paired with `kvitt-server pair-device` (the CLI has no partner-invite subcommand: small ops request for a later server plan); Home showed the account; the offline expense showed the pending marker and synced after reconnect (pending 0, the server has the row); the owner's device registered `fcm_token` and `app_version_name`; a push by `fid` was delivered and the notification tap worked. Still unverified on the phone: the status-bar fix (next install) and the design-spec §2.7 typeface check (the owner looked, no complaint).
|
||||
- M8b outcome (SPEC v0.15): invite-code field holds the raw code, hyphens as a `VisualTransformation` (cursor bug fixed, unit test); quick-row selected badge drawn above the ripple clip; `KvittTopAppBar` pads for the status-bar inset (`windowInsets` parameter), `KvittScaffold` follows; chart bars top 4, bottom 2 dp (D-097); 221 goldens re-recorded. `FcmMessageBody.fid` in `:data` followed (`09f474f`).
|
||||
- M8c, R8 and M8d outcome (SPEC v0.16): goldens `<name>_sv_light`, `_sv_dark`, `_en_light` plus `_sv_light_200`, at 1x (`w411dp-h<height>dp-mdpi`), oxipng-compressed: 1143 PNGs / 131 MB to 865 / 26 MB, mock-ups 36.8 to 26.0 MB (D-098, revises D-066); S-22 has no licences row, `settings_about_licences` gone (D-099, OQ-5 closed); release APK R8-shrunk, about 11 MB (was 43 MB), `mapping.txt` to be kept beside the APK by the publish script (SPEC §10.6); release signing verified (alias `kvitt`, RSA 4096, v2); S-7 options as four fixed rows `EditorOptionRows`, connected buttons 8 dp side padding (D-102).
|
||||
- Owner answers 2026-10-18: "boende" keeps suggesting `travel` (no change); the 128 px picture size is not needed; OQ-5 "no, hide the button" (implemented by M8c); the account page split bar stays as designed; M2c-pi becomes an owner-run bundle (D-100); the keystore lives at the repository root (D-101); the Gitea push waits for fewer goldens and a history rewrite, no LFS.
|
||||
- M12e outcome (recorded in SPEC v0.13 as D-086 to D-095): E-3 `invite_kind` and `Pairing`, S-2 only after a `partner` pairing (D-086); admin name in E-12 links via `?from=`, passed on by E-4, S-1 help line names the admin (D-087); `SyncSummary.lastAttemptFailed` (D-088); `Rejection.actor` (D-089); `X-Kvitt-App-Version-Name`, migration 0003, server schema 3, S-20 "Kvitt 1.1" (D-090); `NewRecurringTemplate` (D-091); `UpdateCheck` (D-092, revises D-073); `SettleState.untouched` (D-093, revises D-074); D-027 re-stamp in `:data` (D-094); `PushEvent` in `:core:model`, six screen-hosted snackbar hosts, snackbar resource ids, adaptive vector launcher icon (D-095, revises D-071). 128 px picture size: the owner confirmed it is not needed (single 512 size, SPEC §14.2.4).
|
||||
- Compatibility: the M12e APK cannot pair or list devices against a pre-M12e server (DTOs without defaults, by design), so the server is rebuilt and redeployed before the new APK is installed (SPEC §14.8). Old phones on the new server work.
|
||||
- In flight: `agent-docs-v017` (this docs change: SPEC v0.17, D-103 to D-108), an AC-coverage audit (its report to be committed later as `docs/validation/ac-coverage.md`). Then a one-off history rewrite (drop the superseded PNG blobs; no clone exists) and the first push to `origin` (owner authorised, no confirmation needed), which also triggers the Gitea Actions workflow.
|
||||
- Remote: `origin` on Gitea exists and the SSH key works; the golden reduction (M8c) has landed; the history rewrite and the first push follow this docs pass (owner authorised 2026-10-18, no further confirmation). The owner created the Gitea secret `kvitt_cicd` and the Drive token (`infra/secrets/rclone-drive-token.json`, turned into `infra/secrets/rclone.conf` with `[gdrive]` `type`, `scope`, `token`; the folder id stays `RCLONE_FOLDER_ID` in `.env`; both git-ignored); the cert-sync key `infra/secrets/ha_ssh_key` exists.
|
||||
- `main` at `b985ce9` (the server overhaul, landed after M12f's `a0259ab`) plus the SPEC v0.18 docs commit from `agent-docs-v018` once it lands. `origin/main` (Gitea) at `18c527f`; everything after it is local until the next push.
|
||||
- History rewrite and first push, 2026-10-18 (owner authorised): superseded PNG versions were dropped from the whole history (no LFS), the current goldens and UX mock-ups restored in `18c527f`; pack 45 MiB; `origin/main` pushed at `18c527f`. A bundle of the pre-rewrite history (`kvitt-pre-rewrite.bundle`) is kept outside the repository, in the orchestrator's scratchpad. Every commit from M2b on got a new hash; the oxipng pass (`7c453d8` before the rewrite) no longer exists as a commit (it only touched PNGs). SPEC, `docs/decisions.md`, this file and `prompts/README.md` cite the rewritten hashes since v0.18 (`7c453d8` stays as the oxipng pass's name; `docs/validation/ac-coverage.md` keeps its pre-rewrite hashes verbatim); plans, spike reports and READMEs may still cite pre-rewrite hashes: find a commit by its subject with `git log --oneline --grep`.
|
||||
- History (rewritten hashes): `5e1be38` plans and prompts, `c885aba` M2c-dev, `76ee957` SPEC v0.3, `c277ee3` M2b, `06f48ef` M2a, `6dce4c7` SPEC v0.4, `7869ec4` M3, `8f0e156` M5, `853c038` SPEC v0.5, `15056dc` M4, `d9dd584` SPEC v0.6, `50339ae` M9, `86e08a1` SPEC v0.7, `aa765bb` M12a, `d39eb2c` SPEC v0.8, `b09f322` M12c, `6eaccec` M12b, `0006bd7` UX Kalas categories and tokens, `6da6b1b` UX sprint U2, `e676812` SPEC v0.9, `557af7e` M12d, `7730a31` M6, `9ee67d4` SPEC v0.10, `a41f240` and `6453932` app wiring before M8, `1ea752c` M7a, `ea7d494` M7e, `7380e50` M7d, `0e1d99d` M7b, `0b140aa` M7c, `c4ab35f` M7f, `b24c8b5` M6b, `f4dc10c` SPEC v0.11, `3dda414` M7g, `cb832a7` and `3d9eea8` M8, `6159e18` SPEC v0.12, `8c60715` M12e, `b7b7483` M12e launcher icon, `51d6ff8` SPEC v0.13, `a312758` Vico removal, `f56dcbe` FCM `fid`, `3e6c337` Pi image arm64 check, `e2dba84` SPEC v0.14, `328c466` M8b, `6eb3f85` `FcmMessageBody.fid`, `bfde12c` SPEC v0.15, `75b549f` M8c goldens, `a0c25b0` M8c licences row, `c30a49e` R8 release build, `bacbd18` M8d, `bfc3acb` SPEC v0.16, `2476667` M2c-pi bundle, `a59abeb` M8e, `b4d9467` Dockerfile `CARGO_BUILD_JOBS`, `956908a` M8f, `1328afe` chips cleanup, `400eac9` SPEC v0.17, `18c527f` goldens restored after the rewrite; then `2fac1ec` to `e70fe0d` infra overhaul, `8660b7f` server gap pass, `7fb86f5` infra security, `dc7a296` to `a0259ab` M12f.
|
||||
- Landed since SPEC v0.17 (recorded in v0.18):
|
||||
- Infra overhaul (`2fac1ec`, `61f92c8`, `fc6126c`, `b647faf`, `e70fe0d`; no decision): `tools/gradle-lock.sh` shared by `gradle-serial.sh`, `clean-builds.sh` and `infra/build-images.sh`; the pre-commit hook runs through `gradle-serial.sh` with JDK 25 on `PATH` (hooks reinstalled in `main` after `e70fe0d`); `install.sh` keeps the deployed `KVITT_TAG`; `--provenance=false` on buildx pushes, the workflow token through env; `RCLONE_REMOTE` dropped from the dev env.
|
||||
- Server gap pass (`8660b7f`, D-113): `kvitt-server invite-partner` (0 ok, 2 household full, 3 no admin), so a scripted partner needs no second admin device; `push sent` info line; CLI tests (`invite-partner`, `migrate`, `healthcheck`, SIGTERM drain); `tools/contracts-check.py` 134 checks.
|
||||
- Infra security (`7fb86f5`, D-117): Caddy log redaction of `/i/<code>` and query strings, CSP and three more response headers, Caddy non-root (uid 10002, read-only, caps dropped), `/certs` 0750, dev stack mounts only the FCM key, `/opt/kvitt/deployed-digests` with a WARNING on change, `kvitt_cicd` with `write:package` only, the plain root key (old variant B) not acceptable.
|
||||
- M12f (`dc7a296`, `5b2ed37`, `2bd6b58`, `c366fbd`, `a0259ab`; D-109 to D-112, D-116): S-16 lost version read-only, S-22 "<version> (schema <n>)" from `/health`, `SettlementRepository` returns null instead of throwing, E-17 retry after each successful sync, invite links dropped while paired, private notifications on the lock screen, `localeFilters` en/sv, `:data` tests (429, D-040, WorkManager via `work-testing`), the home/account screenshot harness fix (stale `sv_dark` goldens re-recorded), 19 unused string keys removed (`strings.csv` 562 rows). Gate at landing: 941 tests. Release APK 10.0 MB.
|
||||
- Validation reports (SPEC §11.4): `docs/validation/ac-coverage.md` (taken at `956908a`, `ed1b130` before the rewrite): 270 rows, 260 Done, 5 Partial, 1 Missing, 4 device-only; feature complete in code, not yet against §4's acceptance rule; its S-16 and S-22 mismatches are fixed by M12f. `docs/validation/security-review.md` (taken at `18c527f`): Critical 0, High 1, Medium 3, Low 10, Info 8; L-6 kept (D-116), L-7 fixed (D-116), L-1, L-2, L-5, L-9, M-2 fixed (D-117), L-8 fixed (`e70fe0d`); H-1 (`725901c`, D-115), M-3 (`baa5806`) and L-4 (`b985ce9`, D-114) fixed by the server overhaul; L-10 left as the spec says, decision pending (§4); M-1 and L-3 wait for the owner (§4). H-1 must be fixed before port 8443 is opened.
|
||||
- Server overhaul (landed on `main` `8103dae` to `b985ce9`): shared helpers and one test harness, clippy pedantic wins; H-1 rate limiter (`725901c`, D-115), pictures at most 16 MP and 64 MB decoded (`baa5806`, D-114), `fcm_token` at most 512 characters (`b985ce9`, D-114); shared row inserts, invite creation and CLI helpers, `tests/common/` harness, synchronous `tasks::start`; 268 server tests; all crates at their latest versions. Recorded in SPEC v0.18.
|
||||
- In flight: the Android overhaul agent only (and this docs pass); then a push to `origin`.
|
||||
- Earlier outcomes (details in SPEC §11.2, §11.3 and `docs/decisions.md`): M8 end-to-end test passed on the owner's S26 against the dev server on 2026-10-18 (pairing, scripted partner, offline expense synced, push by `fid` delivered); M8b to M8f UI fixes; the M2c-pi bundle `infra/pi/` (D-103 to D-106, owner checklist in `infra/README.md` "Pi: what the owner does"); release builds R8-shrunk and signed (alias `kvitt`, RSA 4096, v2).
|
||||
- Compatibility: an APK from M12e on cannot pair or list devices against a pre-M12e server, so the server is rebuilt and redeployed before a new APK is installed (SPEC §14.8). The dev server already runs schema 3.
|
||||
- Remote: `origin` on Gitea, SSH key works. The owner created the Gitea secret `kvitt_cicd` and the Drive token (`infra/secrets/rclone.conf`, `[gdrive]`; folder id in `.env` as `RCLONE_FOLDER_ID`); the cert-sync key `infra/secrets/ha_ssh_key` exists (all git-ignored). The first push triggered the Gitea Actions workflow; its result is the owner's §3 item 1.
|
||||
- Both gates exist: Android `tools/gradle-serial.sh check` (from `android/`), server `cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test` (from `server/`). Both green on `main` as far as reported.
|
||||
- The UX sprint branch `UX-sprint` and its worktree `~/orca/workspaces/kvitt/UX-sprint` were removed on 2026-10-18 (fully merged).
|
||||
- Importer: the dry run of 2026-10-18 with M12b's mapping reconciled on both real files (Vardag 1746 rows, 0 unmapped; Hemma 37 rows, 0 unmapped). The CSV files stay in `export/` (git-ignored).
|
||||
- Development stack (M2c-dev): running on the Mac, reachable at `http://192.168.1.210:8080`; rebuilt on 2026-10-18 with the M12e server and the `fid` target (a push by `fid` arrived in the M8 test), database at schema 3, data kept. Backups `infra/dev/backups/kvitt-20261018T093143Z.sqlite.gz` (before schema 2) and `infra/dev/backups/kvitt-20261018T130443Z.sqlite.gz` (before schema 3) exist (git-ignored). On this Podman setup `infra/dev/up.sh` alone does not swap in a rebuilt image: run `infra/dev/up.sh --down`, then `infra/dev/up.sh`. The owner's phone paired with the bootstrap code on 2026-10-18; a scripted partner exists, joined through a second admin device paired with `kvitt-server pair-device` (tokens held by the orchestrator outside the repo). Firebase project `kvitt-1337` with apps `se.hagstedt.kvitt` and `se.hagstedt.kvitt.debug`; service account `kvitt-fcm`; `infra/secrets/fcm-service-account.json` and `infra/secrets/google-services.json` in the main checkout (git-ignored).
|
||||
- Installed on the owner's phone (SM-S942B): the debug app `se.hagstedt.kvitt.debug`, paired against the dev server for the M8 test on 2026-10-18; the next install carries M8b to M8f.
|
||||
- Importer: the dry run of 2026-10-18 reconciled on both real files (Vardag 1746 rows, Hemma 37 rows, 0 unmapped). The CSV files stay in `export/` (git-ignored).
|
||||
- Development stack (M2c-dev): running on the Mac at `http://192.168.1.210:8080`, database at schema 3, data kept; backups `infra/dev/backups/kvitt-20261018T093143Z.sqlite.gz` and `kvitt-20261018T130443Z.sqlite.gz` (git-ignored). On this Podman setup run `infra/dev/up.sh --down`, then `infra/dev/up.sh`, to swap in a rebuilt image. Since `7fb86f5` `up.sh` copies only `fcm-service-account.json` into `infra/dev/secrets/` (git-ignored). The owner's phone is paired with it; a scripted partner exists (tokens held by the orchestrator outside the repo). Firebase project `kvitt-1337` with apps `se.hagstedt.kvitt` and `se.hagstedt.kvitt.debug`; service account `kvitt-fcm`.
|
||||
- Installed on the owner's phone (SM-S942B): the debug app `se.hagstedt.kvitt.debug`, paired against the dev server; the next install carries M8b to M8f and M12f.
|
||||
- Disk: the MacBook had about 400 MB free during this docs pass (2026-10-18); run `tools/clean-builds.sh` before the next Gradle build.
|
||||
|
||||
## 2. Open work (one line each, with who owns it: agent or owner)
|
||||
- Land `agent-docs-v017` (orchestrator): SPEC v0.17, D-103 to D-108, HANDOFF, `prompts/README.md`, design-spec §2.11, §3.7 and S-19.
|
||||
- AC-coverage audit (agent, running): report to `docs/validation/ac-coverage.md`, committed later.
|
||||
- History rewrite (drop superseded PNG blobs; no clone exists), then the first push to Gitea `origin` (orchestrator; owner authorised, no confirmation needed); the push triggers the Gitea Actions workflow (§3 item 1).
|
||||
- Land `agent-docs-v018` (orchestrator): SPEC v0.18, D-109 to D-117, `docs/validation/ac-coverage.md`, `docs/validation/security-review.md`, HANDOFF, `prompts/README.md`, design-spec S-16, S-22 and the S-1 permission line.
|
||||
- L-10 (a member gets `forbidden` rather than `not_found` for another user's device, so the id's owner is visible): left as the spec says; owner decision pending (§4).
|
||||
- Tooling request (no plan yet): `cargo-audit` in the server gate.
|
||||
- Android overhaul (agent, running).
|
||||
- `infra/README.md` lines (infra agent, no plan yet): drop "(milestone M2a)" on the `build.sh` server line; a `buildx rm` note for the builder config; the operations table still says "APKs about 20 MB each" (10 MB since R8, SPEC §10.10).
|
||||
- Audit items still open: the AC-18.2 restore drill (`docs/validation/restore-drill.md`, M10); AC-18.1, AC-20.1 and AC-16.3 shown on the Pi and phones (M2c-pi, M10); a `KvittWorkerFactory` test (Android agent); an S-1 design state if the owner wants a confirm step for an unusual server (OQ-6, default not in v1).
|
||||
- Unverified risk: the workflow pushes a git tag; whether that re-triggers the path-filtered workflow is not known (watch the first runs).
|
||||
- Push the commits after `18c527f` to `origin` (orchestrator, when the owner asks; pushes need an explicit ask).
|
||||
- Install the next debug build and have the owner look (§3 item 2); build a signed release for the smoke taps (§3 item 3).
|
||||
- Owner runs the M2c-pi bundle on the Kvitt Pi (§3 item 4); record the add-on key variant (A/B) in `infra/README.md` and the router-forward answer.
|
||||
- Cleanup (agents of the owning modules, no plan yet): 20 unused strings R8 found (`editor_next`, `home_notification_rationale`, `settle_empty_settled`, `home_sync_status_tag_*`, …) could be deleted by their modules; optional `localeFilters` en+sv.
|
||||
- Ops request (no plan yet): a `kvitt-server` subcommand for a partner invite, so a scripted partner needs no second admin device.
|
||||
- Plans (SPEC §11.2 v0.17), in dependency order; prompt `prompts/<id>.md`:
|
||||
- M1, M2a, M2b, M2c-dev, M3, M4, M5, M6, M6b, M7a to M7g, M8 (phone test passed), M8b to M8f, M9, M12a to M12e, U1, U2, R8 release build, M2c-pi bundle: landed.
|
||||
- Next: the owner runs the M2c-pi bundle on the Kvitt Pi (D-100); M10 First release after it (keystore per §10.6, D-101); M11 Import history after M9 and M10 (procedure §10.8 "Production run", D-025; each run must reconcile, D-045).
|
||||
- Owner runs the M2c-pi bundle on the Kvitt Pi (§3 item 5); record the accepted cert-sync key form and the router-forward answer in `infra/README.md`.
|
||||
- Plans (SPEC §11.2 v0.18), in dependency order; prompt `prompts/<id>.md`:
|
||||
- M1, M2a, M2b, M2c-dev, M3, M4, M5, M6, M6b, M7a to M7g, M8 (phone test passed), M8b to M8f, M9, M12a to M12f, U1, U2, R8 release build, M2c-pi bundle, server gap pass, infra overhaul, infra security and the server overhaul: landed.
|
||||
- Next: the Android overhaul; a server image with the H-1 fix before the router forward; the owner runs the M2c-pi bundle on the Kvitt Pi (D-100); M10 First release after it (keystore per §10.6, D-101); M11 Import history after M9 and M10 (procedure §10.8 "Production run", D-025; each run must reconcile, D-045).
|
||||
|
||||
## 3. HUMAN steps pending (relay in chat)
|
||||
1. After the first push: tell me whether the Gitea Actions run ("Build Kvitt images") succeeded and how long it took.
|
||||
2. Next install on the phone (yes/no each): screen changes are instant, with no fade or slide; plus the earlier checks: the title bar sits below the status bar; the quick-row selected badge is whole; the invite-code field cursor stays after the last character; the expense editor shows Konto, Datum, Betalt av, Delning as four rows that do not move when a value changes; the recurring editor shows Konto, Betalt av, Delning as three such rows; "Household" fits its half of the Analytics filter bar.
|
||||
3. Release build smoke taps: the app opens; S-1 or Home renders; Settings, About shows the version; add one expense and watch it sync.
|
||||
4. Pi, after the app is proven: the nine steps of `infra/README.md` "Pi: what the owner does":
|
||||
1. Gitea, the repository, Actions: did the run "Build Kvitt images" triggered by the first push succeed (yes/no), and how long did it take?
|
||||
2. Next install on the phone (yes/no each): screen changes are instant, with no fade or slide; Settings, Om Kvitt shows the server version as "… (schema 3)"; if Inställningar, Synkstatus lists a change under "Ändringar som inte synkades" (likely none), "Öppna" shows "Din version" with "Visa nuvarande version"; plus the earlier checks: the title bar sits below the status bar; the quick-row selected badge is whole; the invite-code field cursor stays after the last character; the expense editor shows Konto, Datum, Betalt av, Delning as four rows that do not move when a value changes; the recurring editor shows Konto, Betalt av, Delning as three such rows; "Household" fits its half of the Analytics filter bar.
|
||||
3. Release build smoke taps: the app opens; S-1 or Home renders; Settings, Om Kvitt shows the version; add one expense and watch it sync.
|
||||
4. Owner decisions from the security review (answer each):
|
||||
1. M-1: encrypt the Drive backups through an rclone `crypt` remote and re-authorise rclone with the narrower `drive.file` scope (a restore then needs the crypt passwords)? yes/no.
|
||||
2. M-2: which cert-sync key form did the Home Assistant add-on accept at Pi step 3: the restricted root key (variant A) or a dedicated non-root user? (A plain root key is not acceptable.)
|
||||
3. L-3: a separate per-IP limit for APK downloads (`/apk/files/*`): which number per minute (assumed 10 per minute per IP)?
|
||||
4. Gitea token: if the workflow's tag push fails with `kvitt_cicd` limited to `write:package`, may `write:repository` be added? yes/no.
|
||||
5. Confirm the numbers the server overhaul assumed and built: pictures capped at 16 megapixels; `fcm_token` at most 512 characters. yes/no.
|
||||
5. Pi, after the app is proven: the nine steps of `infra/README.md` "Pi: what the owner does":
|
||||
1. Provision: Raspberry Pi Imager, Raspberry Pi OS Lite (64-bit), user, SSH key, time zone; static DHCP lease in the router.
|
||||
2. Docker Engine from Docker's Debian arm64 repository; `docker run --rm hello-world` prints "Hello from Docker!".
|
||||
3. Home Assistant, Settings, Add-ons, the SSH add-on, Configuration, `authorized_keys`: add the cert-sync key as variant A (restricted `tar` command); if the add-on refuses it, variant B (plain key). Question: which variant was accepted, A or B?
|
||||
3. Home Assistant, Settings, Add-ons, the SSH add-on, Configuration, `authorized_keys`: add the restricted cert-sync key line (variant A); if the add-on refuses it, a dedicated non-root user that can only read the certificate directory; never a plain root key. Question: which form was accepted?
|
||||
4. On the Mac: `infra/pi/.env` from `.env.example`, every `CHANGE_ME` replaced; secrets staged into `infra/pi/secrets/`.
|
||||
5. `scp` the bundle to the Pi, remove `infra/pi/secrets` on the Mac; on the Pi `ssh-keyscan` the Home Assistant host into `secrets/ha_known_hosts` (at least 1 line).
|
||||
6. `./install.sh` on the Pi; expected end "Kvitt is running."; then remove `~/kvitt-pi/secrets`.
|
||||
7. Router, WAN, Virtual Server / Port Forwarding: TCP 8443 to the Kvitt Pi's 8443; on the phone with Wi-Fi off, `https://icehack.asuscomm.com:8443/health` shows `"status":"ok"` without a certificate warning. Question: yes/no?
|
||||
7. Router, WAN, Virtual Server / Port Forwarding: TCP 8443 to the Kvitt Pi's 8443 (only after the H-1 fix is deployed); on the phone with Wi-Fi off, `https://icehack.asuscomm.com:8443/health` shows `"status":"ok"` without a certificate warning (yes/no); then the `remote_ip` check of the README's operations table shows a public address (yes/no).
|
||||
8. `/opt/kvitt/backup-now.sh` ends with "last-success: <stamp>"; `/opt/kvitt/bootstrap.sh` prints the admin invite code (first install only).
|
||||
9. New versions: `/opt/kvitt/deploy.sh v1.0.N` after the Gitea workflow pushed that tag.
|
||||
9. New versions: `/opt/kvitt/deploy.sh v1.0.N` after the Gitea workflow pushed that tag; it prints the image digests and warns if a recorded tag changed digest.
|
||||
|
||||
## 4. Owner questions (asked, unanswered)
|
||||
- None. OQ-3 is answered by placeholders (D-100); OQ-5 answered and implemented (D-099).
|
||||
- The §3 item 1 workflow result and duration.
|
||||
- The five security-review decisions of §3 item 4 (M-1 backup encryption, M-2 key form, L-3 APK download rate, `write:repository`, the 16 MP and 512-character assumptions).
|
||||
- OQ-6 (SPEC §12): a confirm step on S-1 for an unusual server; default "not in v1".
|
||||
- Security review L-10: should a member get `not_found` instead of `forbidden` for a device id of the other user (hides whose it is)? As built and as the spec says: `forbidden`.
|
||||
|
||||
## 5. Paused (waiting on something outside the repo)
|
||||
- Nothing.
|
||||
|
||||
## 6. Numbering
|
||||
- Decisions: D-001 to D-108 used except D-008 and D-009. Next free: **D-109**.
|
||||
- Spec version: v0.17 written; next **v0.18**.
|
||||
- Server schema version **3** (migration 0003, landed with M12e); next **4**. Room schema version **1** (`android/data/schemas/se.hagstedt.kvitt.data.db.KvittDatabase/1.json`); next **2**. Both unchanged by v0.17.
|
||||
- Decisions: D-001 to D-117 used, except D-008 and D-009 (never used); none reserved. Next free: **D-118**.
|
||||
- Spec version: v0.18 written; next **v0.19**.
|
||||
- Server schema version **3** (migration 0003); next **4**. Room schema version **1** (`android/data/schemas/se.hagstedt.kvitt.data.db.KvittDatabase/1.json`); next **2**. Both unchanged by v0.18.
|
||||
- Sync protocol **1**, push payload **1**.
|
||||
|
||||
## 7. How the work is run
|
||||
|
||||
Reference in New Issue
Block a user