Plans and start prompts for every milestone; SPEC v0.2

PLAN-<id>.md for U1, U2, M1, M2a, M2b, M2c-dev, M2c-pi, M3, M4, M5, M6,
M7a-M7f, M8, M9, M10, M11, each with the eleven fixed sections, and a
start prompt per plan in prompts/ plus prompts/README.md (dependency
order and parallel waves).

SPEC v0.2: owner answers D-001 (development-first, M2c split into
M2c-dev and M2c-pi, Gitea registry), D-002 (local backups deleted once
on Drive), D-003 (Splitwise CSV format, English and Swedish variants,
category mapping), OQ-1, OQ-2, OQ-4 answered; M1's readings of
ambiguous contract points stated explicitly in §14.3 to §14.5.
HANDOFF §2 lists the plans.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 21:05:34 +02:00
parent c6df2ab8f5
commit 5e1be38364
46 changed files with 2398 additions and 54 deletions
+73
View File
@@ -0,0 +1,73 @@
# PLAN-M1: Contracts and vectors
On record only: M1 was implemented in parallel by an agent working directly from SPEC §14 and §9 and landed on `main` as `c6df2ab`; its readings of ambiguous points are stated in SPEC v0.2. This plan describes the same scope; if the two disagree, SPEC wins.
## 1. Goal
Write the cross-team contract files from SPEC §14: the OpenAPI document, the SQLite schema v1, the shared test vectors, the JSON examples, and a stdlib-only Python checker. After M1 lands, server and Android agents work in parallel against these files without talking to each other.
## 2. Read first
1. SPEC §14 Contracts: §14.1 SQLite schema v1, §14.3 OpenAPI 3.1 outline (14.3.1 to 14.3.5), §14.4 Sync protocol v1 (examples), §14.5 Domain rules as pure functions (14.5.1 to 14.5.5), §14.6 Push payload v1, §14.7 Module layout and ownership map, §14.8 Contract files and the change rule.
2. SPEC §9.1 Splits, §9.3 Balances, §9.4 Settlement allocation proposal, §9.6 Limits and validation.
3. SPEC §7 API outline (endpoint ids E-1 to E-33).
4. SPEC §11.2 (row M1) and §11.3 (note M1).
5. `CLAUDE.md`.
## 3. Already established
- The OpenAPI file is written by hand from §14.3, OpenAPI 3.1.0, `info.title` `Kvitt`, `info.version` `1`, one server `https://icehack.asuscomm.com:8443`, security scheme `device` = HTTP bearer; the outline is binding and the YAML adds or drops nothing (§14.3, §11.3).
- `contracts/schema/server-v1.sql` is the §14.1 DDL byte for byte; M2a's `0001_init.sql` must equal it (§14.1).
- Vector files, one per function: `compute_split.json`, `compute_balances.json`, `propose_allocation.json`, `validate_settlement.json`, `over_settled_accounts.json`, `spend_series.json`, `resolve_range.json`; format of §14.5.5; minimum cases listed in §14.5.5.
- Examples: one per request and response body of §14.3.4 in `contracts/examples/<E-id>-<name>/{request,response}.json`, one per error code in `contracts/examples/errors/<code>.json`, the sync examples of §14.4 in `contracts/examples/sync/`, push examples in `contracts/examples/push/` (§14.3.5, §14.7).
- Error codes are exactly the 25 of §14.3.2; error tokens exactly those of §14.5.3.
- Ratio rule rounds the non-payer down; payer absorbs the remainder (§9.1). Proposal algorithm §9.4 is normative.
- A contract change after landing needs a spec bump and a decisions entry (§14.8).
## 4. Owned paths
From SPEC §14.7, verbatim: `contracts/**`, `tools/contracts-check.py` (owner M1; after the owner lands: contract-change plans only (§14.8)).
Edit nothing outside these paths; a needed change elsewhere is a contract request to the orchestrator.
## 5. Deliverables
- `contracts/openapi.yaml`: OpenAPI 3.1.0 document of §14.3 (every endpoint E-1 to E-33, wire objects, error responses).
- `contracts/schema/server-v1.sql`: the §14.1 DDL, byte for byte.
- `contracts/test-vectors/compute_split.json`, `compute_balances.json`, `propose_allocation.json`, `validate_settlement.json`, `over_settled_accounts.json`, `spend_series.json`, `resolve_range.json`: vectors per §14.5.5 with at least its minimum cases.
- `contracts/examples/<E-id>-<name>/{request,response}.json`: one per request and response body of §14.3.4.
- `contracts/examples/errors/<code>.json`: one per error code of §14.3.2.
- `contracts/examples/sync/*.json`: pull page, push request, push response with accepted and rejected results (§14.4).
- `contracts/examples/push/*.json`: one FCM message per push type of §14.6.
- `tools/contracts-check.py`: stdlib-only checker (JSON parses, vector format, Python reference of §9.1, §9.3, §9.4, example key sets against §14.3 shapes).
## 6. Steps
1. Worktree. From the main checkout `/Users/jhag/projects/kvitt`: `git worktree add .claude/worktrees/agent-m1 -b agent-m1 main`, then in `.claude/worktrees/agent-m1`: `git reset --hard main`. No git-ignored files are needed; copy none. Run `tools/install-git-hooks.sh`.
2. Read §2 in order.
3. Copy the §14.1 DDL into `contracts/schema/server-v1.sql` exactly (no trailing changes); verify with a byte comparison against the block extracted from SPEC.md.
4. Write `tools/contracts-check.py` first (Python 3 stdlib only): JSON parse of every file under `contracts/`; vector envelope (`format` 1, `function`, `cases` with `name`, `input`, `expected` holding `ok` or `error`); reference implementations of `compute_split`, `compute_balances`, `propose_allocation`, `validate_settlement`, `over_settled_accounts` per §9.1, §9.3, §9.4 and §14.5.2 recomputing every expected value; key-set validation of each example against the wire shapes of §14.3.3 and the endpoint bodies of §14.3.4.
5. Write the vector files with the §14.5.5 minimum cases (and the §9.1 example table rows); run the checker after each file. For `spend_series` and `resolve_range` (Kotlin only) the checker validates format and that dates are well formed; state in the report whether it also recomputes them.
6. Write the examples, using UUIDv7-shaped ids and the fixed timestamp form; run the checker.
7. Write `contracts/openapi.yaml` from §14.3; cross-check every endpoint, status code and error list against §14.3.4 and the always-possible codes of §14.3.2. Python stdlib has no YAML parser: state in the report how the YAML was checked.
8. Run the gate (§7). Commit on `agent-m1`, `git rebase main`, run the gate again. Never merge, push or remove the worktree.
## 7. Gate
From SPEC §11.2, verbatim: "`python3 tools/contracts-check.py` passes: all JSON parses, every vector file matches §14.5.5, a stdlib-only Python reference of §9.1, §9.3, §9.4 reproduces every expected value, every example validates against the shapes of §14.3 by key set".
Command: `python3 tools/contracts-check.py` from the repository root. Green means exit code 0 and its summary line reporting zero failures.
## 8. HUMAN steps
From SPEC §11.2, verbatim: "none".
## 9. Out of scope
- Any Rust or Kotlin code (M2a, M2b), including the utoipa annotations (M2a) and DTOs (M5).
- The server migration file `server/crates/kvitt-server/migrations/0001_init.sql` (M2a).
- The Room exported schema `android/data/schemas/**` (M5).
- Changing §14 of the spec; anything that would is a gap for the report.
- `docs/`, `SPEC.md`, `CLAUDE.md`, other `tools/` files.
## 10. Report
- Branch `agent-m1`, head commit hash after rebasing on `main`.
- Gate: the checker's output summary lines (files, cases, examples, failures) from this session.
- Count of vector cases per function; list of example directories.
- How the YAML was checked; whether `spend_series`/`resolve_range` are recomputed.
- Versions chosen: Python version used (no third-party packages).
- Numbering used (decision ids, spec version) or `TODO(spec)` occurrences.
- Open questions and spec gaps (any place §14 is ambiguous or self-contradicting), 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.