SPEC v0.4: M2a and M2b decisions, handoff to the real state

Records the decisions proposed in the M2a (fdf2093) and M2b (fad6fc9)
reports: D-005 OpenAPI equality normalisations and CommonRules, D-006
bp_sum_not_10000 token, D-007 per-crate no-unwrap deny, D-010 Roborazzi,
D-011 IncompleteCustomRangeException, D-012 Room 3 with M2b's entities and
1.json as a contract file, D-013 JDK 25 Robolectric flags, D-014
failOnNoDiscoveredTests (D-008, D-009 unused). Clarifications in §6, §8.2,
§8.6, §9.6, §10.3, §10.4, §11, §14.2, §14.3, §14.5, §14.7, §14.8 and
AC-11.7. PLAN-M5 builds on the existing entities; v0.4 readings added to
PLAN-M3, M5, M7b to M7f. HANDOFF rewritten: next free D-040, spec v0.5,
server schema 2, Room schema 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 21:40:42 +02:00
parent 06f48ef9e9
commit 6dce4c73a9
14 changed files with 143 additions and 81 deletions
+38 -28
View File
@@ -3,42 +3,52 @@
Living document, rewritten in place (never a second copy). A new orchestrator session reads CLAUDE.md, then this.
## 1. Where things stand
- `main` at `c885aba` (M2c-dev) on top of `5e1be38` (plans, prompts, SPEC v0.2); after this docs change lands, `main` also carries SPEC v0.3 (branch `agent-spec3`). Landed: M0 spec, M1 contracts and vectors (`c6df2ab`), M2c-dev infra for development (`c885aba`). No server or Android project yet, so neither gate runs.
- Worktrees in flight under `.claude/worktrees/`: `agent-m2a` (M2a server skeleton and `kvitt-domain`), `agent-m2b` (M2b Android skeleton and `:domain`), `agent-spec3` (this docs change: SPEC v0.3, D-004, D-015 to D-025). Both M2 agents started from `5e1be38`; their briefs carried the orchestrator's resolutions that v0.3 now records.
- The owner runs the UX sprint (U1, then U2) in a separate Claude session in the worktree `~/orca/workspaces/kvitt/UX-sprint` on branch `UX-sprint` (based on `cab3e93`, SPEC v0.1); it commits only under `docs/ux/` and rebases on `main` before landing.
- Development infrastructure exists (M2c-dev): `infra/dev/` compose stack on the Mac (server and on-demand backup, no Caddy, no TLS), Firebase on project `kvitt-1337` with Android apps `se.hagstedt.kvitt` and `se.hagstedt.kvitt.debug`, service account `kvitt-fcm` with `roles/firebasecloudmessaging.admin`; `infra/secrets/fcm-service-account.json` and `infra/secrets/google-services.json` in the main checkout (git-ignored). The dev stack's health check from the phone is a HUMAN step and waits for M2a's image.
- Installed on the owner's phone: nothing.
- `main` at `fdf2093` (M2a) plus the SPEC v0.4 docs commit from `agent-spec4` once it lands. History: `5e1be38` plans and prompts, `c885aba` M2c-dev, `76ee957` SPEC v0.3, `fad6fc9` M2b, `fdf2093` M2a.
- Landed: M0 spec, M1 contracts and vectors (`c6df2ab`), M2c-dev infra for development (`c885aba`), SPEC v0.3 (`76ee957`), M2b Android skeleton and `:domain` (`fad6fc9`), M2a server skeleton and `kvitt-domain` (`fdf2093`). With `agent-spec4`: SPEC v0.4 with D-005 to D-007 and D-010 to D-014 (D-008 and D-009 unused).
- Both gates exist now: Android `tools/gradle-serial.sh check` (from `android/`), server `cargo fmt --check && cargo clippy -- -D warnings && cargo test` (from `server/`).
- Worktrees in flight under `.claude/worktrees/`: `agent-m3` (M3 server core API), `agent-m5` (M5 Android data layer), `agent-spec4` (this docs change: SPEC v0.4).
- The owner runs the UX sprint (U1, then U2) in a separate Claude session in `~/orca/workspaces/kvitt/UX-sprint` on branch `UX-sprint`; it commits only under `docs/ux/` and rebases on `main` before landing.
- Development infrastructure (M2c-dev): `infra/dev/` compose stack on the Mac (server built from `server/Dockerfile`, on-demand backup, no Caddy, no TLS); 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). The M2a image now exists, so the phone health check can run.
- Installed on the owner's phone: nothing yet (M2b's `installDebug` is pending).
## 2. Open work (one line each, with who owns it: agent or owner)
- Land `agent-spec3` (orchestrator): SPEC v0.3, decisions D-004 and D-015 to D-025, plans and prompts with every open point closed, CLAUDE.md numbering rule (implementation agents never edit SPEC or decisions).
- Then record M2a's and M2b's proposed decisions from their reports (D-005 to D-014, including D-010 the screenshot tool) through a docs agent (orchestrator).
- Plans (SPEC §11.2 v0.3), in dependency order; prompt `prompts/<id>.md`:
- Land `agent-spec4` (orchestrator): SPEC v0.4, decisions D-005 to D-014, CLAUDE.md server rules (D-007, `kvitt-domain` deps), PLAN-M2a/M2b "on record", PLAN-M5 (builds on M2b's entities, D-012), v0.4 readings in PLAN-M3, M5, M7b to M7f, prompts/README status.
- Tell `agent-m5` before it lands (orchestrator): M2b already created the Room 3 entities, `KvittDatabase` v1 and `1.json` (D-012); M5 adds DAOs and must not change them; v0.4 readings of §14.2.4 (FieldError `validation_failed`, missing custom date = today, `DrillDownState.title`, settlement row = allocation in an account's list).
- Follow-up in `:core:fakes` (M2b-owned base files; needs a small agent or goes with M5's or M7b's brief): settlement rows in an account's ledger must carry the allocation, not the total (AC-11.7 v0.4); replace the five `TODO(spec)` comments in `android/core/fakes/**` that v0.4 settles; and the `TODO(spec)` in `server/crates/kvitt-domain/src/split.rs` (D-006).
- Plans (SPEC §11.2 v0.4), in dependency order; prompt `prompts/<id>.md`:
- M1 Contracts and vectors: landed (`c6df2ab`).
- M2c-dev Infra for development: landed (`c885aba`); outstanding: phone `/health` check (owner) once M2a's image exists.
- M2a Server skeleton and `kvitt-domain`: landed (`fdf2093`).
- M2b Android skeleton and `:domain`: landed (`fad6fc9`); outstanding: `installDebug` on the phone (owner plugs it in).
- M2c-dev Infra for development: landed (`c885aba`); outstanding: phone `/health` check against the dev stack (owner).
- U1 UX directions: owner's session (`UX-sprint`), in progress; owner then picks a direction.
- U2 UX design spec: owner's session (`UX-sprint`), after U1 and the pick; owner approves; then the §9.7 colour change goes into the spec (docs agent) before M6.
- M2a Server skeleton and `kvitt-domain`: agent in flight (`agent-m2a`).
- M2b Android skeleton and `:domain`: agent in flight (`agent-m2b`); plug the phone in once for `installDebug` (owner).
- M3 Server core API: after M2a.
- M4 Server sync, audit, push, scheduler: after M2a, lands after M3 (D-015).
- M5 Android data layer: after M2b.
- M6 Design system: after U2 approved, M2b and the §9.7 colour change.
- U2 UX design spec: owner's session, after U1 and the pick; owner approves; then the §9.7 colour change goes into the spec (docs agent) before M6.
- M3 Server core API: agent in flight (`agent-m3`).
- M4 Server sync, audit, push, scheduler: can start now (after M2a); lands after M3 (D-015).
- M5 Android data layer: agent in flight (`agent-m5`).
- M6 Design system: after U2 approved and the §9.7 colour change.
- M7a to M7f Features: after M6, in parallel.
- M9 Splitwise importer: after M2a and M4.
- M8 App integration: after M3, M4, M5, M7a to M7f, M2c-dev.
- M9 Splitwise importer: after M4.
- M8 App integration: after M3, M4, M5, M7a to M7f.
- M2c-pi Infra on the Pi: after M8, before M10 (owner: answer OQ-3, grant the Pi, Home Assistant Pi, Gitea and Drive allowances at the start, D-023).
- M10 First release: after M2c-pi, M3, M4, M8 (owner: keystore per §10.6).
- M10 First release: after M2c-pi, M3, M4, M8 (owner: keystore per §10.6, D-024).
- M11 Import history: after M9 and M10.
## 3. Owner questions (asked, unanswered)
- OQ-3 LAN addresses and SSH users of the Kvitt Pi and the Home Assistant Pi; SSH port of the HA Pi; certificate directory there; which SSH add-on (SPEC §12). Needed by M2c-pi only. (OQ-1, OQ-2, OQ-4 are answered: D-001, D-003, §10.9.)
## 3. HUMAN steps pending (relay in chat)
- Plug the phone in over USB so an agent can run `installDebug` of the M2b skeleton (expected: the Kvitt debug app opens to an empty themed screen).
- Dev-stack health check: on the phone on the home Wi-Fi, open the dev server's `/health` and answer yes/no that it shows `"status":"ok"` (M2c-dev).
- UX direction pick from U1's directions, with comments (owner's UX-sprint session).
## 4. Paused (waiting on something outside the repo)
- M2c-dev phone health check: waits for M2a's server image.
## 4. Owner questions (asked, unanswered)
- OQ-3 LAN addresses and SSH users of the Kvitt Pi and the Home Assistant Pi; SSH port of the HA Pi; certificate directory there; which SSH add-on (SPEC §12). Needed by M2c-pi only. The only open question (OQ-1, OQ-2, OQ-4 answered: D-001, D-003, §10.9).
## 5. Numbering
Next free after `agent-spec3`: decision **D-026** (D-001 to D-004 and D-015 to D-025 are used; D-005 to D-014 are reserved for the M2a and M2b agents' proposals, D-010 being the screenshot tool). Spec version: v0.3 written; next **v0.4**. Schema version **1** (defined, not yet implemented); next schema version **2**. Sync protocol **1**, push payload **1**.
## 5. Paused (waiting on something outside the repo)
- Nothing; the M2c-dev phone check no longer waits on M2a, only on the owner.
## 6. How the work is run
See CLAUDE.md › Orchestration. HUMAN steps in reports are relayed in chat by the orchestrator; the owner does not
read them in files.
## 6. Numbering
- Decisions: D-001 to D-025 used (D-008 and D-009 unused). Reserved: **D-026 to D-029 for M5**, **D-030 to D-039 for M3**. Next free for anything else: **D-040**.
- Spec version: v0.4 written; next **v0.5** (the first of M3/M5 to land takes it; the second renumbers on rebase).
- Server schema version **1** (implemented by M2a); next **2**. Room schema version **1** (created by M2b, `android/data/schemas/se.hagstedt.kvitt.data.db.KvittDatabase/1.json`); next **2**.
- Sync protocol **1**, push payload **1**.
## 7. How the work is run
See CLAUDE.md › Orchestration. HUMAN steps in reports are relayed in chat by the orchestrator; the owner does not read them in files.